diff options
1374 files changed, 24201 insertions, 12384 deletions
diff --git a/.github/ISSUE_TEMPLATE/bootstrap.md b/.github/ISSUE_TEMPLATE/bootstrap.md new file mode 100644 index 00000000000..8d72eae8593 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bootstrap.md @@ -0,0 +1,70 @@ +--- +name: Bootstrap (Rust Build System) Report +about: Issues encountered on bootstrap build system +labels: C-bug, T-bootstrap +--- + +<!-- +Thank you for submitting a bootstrap report! Please provide detailed information to help us reproduce and diagnose the issue. +--> + +### Summary + +<!-- +Provide a brief description of the problem you are experiencing. +--> + +### Command used + +```sh +<command> +``` + +### Expected behaviour + +<!-- +Describe what you expected to happen. +--> + +### Actual behaviour + +<!-- +Describe what actually happened. +--> + +### Bootstrap configuration (config.toml) +```toml +<config> +``` + +### Operating system + +<!-- +e.g., Ubuntu 22.04, macOS 12, Windows 10 +--> + +### HEAD + +<!-- +Output of `git rev-parse HEAD` command, or content of the `git-commit-hash` file if using a tarball source. +--> + +### Additional context +<!-- +Include any other relevant information (e.g., if you have custom patches or modifications on the project). +--> + + +<!-- +Include the complete build log in the section below. +Enable backtrace and verbose mode if possible for more detailed information e.g., with `RUST_BACKTRACE=1 ./x build -v`. +--> +<details><summary>Build Log</summary> +<p> + +```txt +<log> +``` + +</p> +</details> diff --git a/.gitignore b/.gitignore index f84a3704ca9..ddc8dad95e8 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,7 @@ __pycache__/ node_modules package-lock.json package.json +/src/doc/rustc-dev-guide/mermaid.min.js ## Rustdoc GUI tests tests/rustdoc-gui/src/**.lock diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eeff563d8ec..a5ddff595f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,15 @@ Documentation for contributing to the compiler or tooling is located in the [Gui Development][rustc-dev-guide], commonly known as the [rustc-dev-guide]. Documentation for the standard library in the [Standard library developers Guide][std-dev-guide], commonly known as the [std-dev-guide]. +## Making changes to subtrees and submodules + +For submodules, changes need to be made against the repository corresponding the +submodule, and not the main `rust-lang/rust` repository. + +For subtrees, prefer sending a PR against the subtree's repository if it does +not need to be made against the main `rust-lang/rust` repostory (e.g. a +rustc-dev-guide change that does not accompany a compiler change). + ## About the [rustc-dev-guide] The [rustc-dev-guide] is meant to help document how rustc –the Rust compiler– works, diff --git a/Cargo.lock b/Cargo.lock index a08d43a014c..10889139e8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,11 +172,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] @@ -254,9 +255,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "blake3" @@ -450,9 +451,9 @@ dependencies = [ [[package]] name = "chrono-tz" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" +checksum = "9c6ac4f2c0bf0f44e9161aec9675e1050aa4a530663c4a9e37e108fa948bca9f" dependencies = [ "chrono", "chrono-tz-build", @@ -733,7 +734,7 @@ dependencies = [ "tracing-subscriber", "unified-diff", "walkdir", - "windows", + "windows 0.59.0", ] [[package]] @@ -1223,7 +1224,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" dependencies = [ "crc32fast", - "miniz_oxide 0.8.2", + "miniz_oxide 0.8.3", ] [[package]] @@ -1524,7 +1525,6 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", - "serde", ] [[package]] @@ -1534,6 +1534,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "foldhash", + "serde", ] [[package]] @@ -1954,9 +1955,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -2152,9 +2153,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "lzma-sys" @@ -2317,9 +2318,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] @@ -3574,7 +3575,7 @@ dependencies = [ "thorin-dwp", "tracing", "wasm-encoder 0.219.1", - "windows", + "windows 0.59.0", ] [[package]] @@ -3632,7 +3633,7 @@ dependencies = [ "tempfile", "thin-vec", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -3694,7 +3695,7 @@ dependencies = [ "shlex", "time", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -3747,7 +3748,7 @@ dependencies = [ "termcolor", "termize", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -4259,7 +4260,6 @@ dependencies = [ "rustc_serialize", "rustc_type_ir", "rustc_type_ir_macros", - "smallvec", "tracing", ] @@ -4480,7 +4480,7 @@ dependencies = [ "smallvec", "termize", "tracing", - "windows", + "windows 0.59.0", ] [[package]] @@ -5183,7 +5183,7 @@ checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" dependencies = [ "core-foundation-sys", "libc", - "windows", + "windows 0.57.0", ] [[package]] @@ -5836,18 +5836,18 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b913a3b5fe84142e269d63cc62b64319ccaf89b748fc31fe025177f767a756c4" +checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" dependencies = [ "getrandom", ] [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -5879,26 +5879,27 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasi-preview1-component-adapter-provider" -version = "24.0.1" +version = "29.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f76d9fa52234153eeb40b088de91a8c13dc28a912cf6f31cd89ca4bac9024e0" +checksum = "dcd9f21bbde82ba59e415a8725e6ad0d0d7e9e460b1a3ccbca5bdee952c1a324" [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", @@ -5910,9 +5911,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5920,9 +5921,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -5933,15 +5934,18 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasm-component-ld" -version = "0.5.11" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b05c3820968b335f10e703218459e4fd2cc91fdfc8f7936a993f1aacaa0938" +checksum = "580305a8e3f1b7a79859a8db897de643533b2851c5eb080fe5800233f16dec88" dependencies = [ "anyhow", "clap", @@ -5949,7 +5953,7 @@ dependencies = [ "libc", "tempfile", "wasi-preview1-component-adapter-provider", - "wasmparser 0.219.1", + "wasmparser 0.223.0", "wat", "windows-sys 0.59.0", "winsplit", @@ -5986,9 +5990,9 @@ dependencies = [ [[package]] name = "wasm-metadata" -version = "0.219.1" +version = "0.223.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af5a8e37a5e996861e1813f8de30911c47609c9ff51a7284f7dbd754dc3a9f3" +checksum = "5c730c3379d3d20e5a0245b0724b924483e853588ca8fba547c1e21f19e7d735" dependencies = [ "anyhow", "indexmap", @@ -5996,8 +6000,9 @@ dependencies = [ "serde_derive", "serde_json", "spdx", - "wasm-encoder 0.219.1", - "wasmparser 0.219.1", + "url", + "wasm-encoder 0.223.0", + "wasmparser 0.223.0", ] [[package]] @@ -6006,12 +6011,8 @@ version = "0.219.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c771866898879073c53b565a6c7b49953795159836714ac56a5befb581227c5" dependencies = [ - "ahash", "bitflags", - "hashbrown 0.14.5", "indexmap", - "semver", - "serde", ] [[package]] @@ -6030,8 +6031,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5a99faceb1a5a84dd6084ec4bfa4b2ab153b5793b43fd8f58b89232634afc35" dependencies = [ "bitflags", + "hashbrown 0.15.2", "indexmap", "semver", + "serde", ] [[package]] @@ -6108,6 +6111,16 @@ dependencies = [ ] [[package]] +name = "windows" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1" +dependencies = [ + "windows-core 0.59.0", + "windows-targets 0.53.0", +] + +[[package]] name = "windows-bindgen" version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6136,13 +6149,26 @@ version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result 0.1.2", "windows-targets 0.52.6", ] [[package]] +name = "windows-core" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce" +dependencies = [ + "windows-implement 0.59.0", + "windows-interface 0.59.0", + "windows-result 0.3.0", + "windows-strings", + "windows-targets 0.53.0", +] + +[[package]] name = "windows-implement" version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6154,6 +6180,17 @@ dependencies = [ ] [[package]] +name = "windows-implement" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] name = "windows-interface" version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6165,6 +6202,17 @@ dependencies = [ ] [[package]] +name = "windows-interface" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] name = "windows-metadata" version = "0.58.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6180,6 +6228,24 @@ dependencies = [ ] [[package]] +name = "windows-result" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08106ce80268c4067c0571ca55a9b4e9516518eaa1a1fe9b37ca403ae1d1a34" +dependencies = [ + "windows-targets 0.53.0", +] + +[[package]] +name = "windows-strings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b888f919960b42ea4e11c2f408fadb55f78a9f236d5eef084103c8ce52893491" +dependencies = [ + "windows-targets 0.53.0", +] + +[[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6230,7 +6296,7 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", @@ -6238,6 +6304,22 @@ dependencies = [ ] [[package]] +name = "windows-targets" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" +dependencies = [ + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6250,6 +6332,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6262,6 +6350,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6274,12 +6368,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6292,6 +6398,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6304,6 +6416,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6316,6 +6434,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6328,6 +6452,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] name = "winnow" version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6344,9 +6474,9 @@ checksum = "3ab703352da6a72f35c39a533526393725640575bb211f61987a2748323ad956" [[package]] name = "wit-component" -version = "0.219.1" +version = "0.223.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1673163c0cb14a6a19ddbf44dd4efe6f015ec1ebb8156710ac32501f19fba2" +checksum = "c10ed2aeee4c8ec5715875f62f4a3de3608d6987165c116810d8c2908aa9d93b" dependencies = [ "anyhow", "bitflags", @@ -6355,17 +6485,17 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "wasm-encoder 0.219.1", + "wasm-encoder 0.223.0", "wasm-metadata", - "wasmparser 0.219.1", + "wasmparser 0.223.0", "wit-parser", ] [[package]] name = "wit-parser" -version = "0.219.1" +version = "0.223.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a86f669283257e8e424b9a4fc3518e3ade0b95deb9fbc0f93a1876be3eda598" +checksum = "92772f4dcacb804b275981eea1d920b12b377993b53307f1e33d87404e080281" dependencies = [ "anyhow", "id-arena", @@ -6376,7 +6506,7 @@ dependencies = [ "serde_derive", "serde_json", "unicode-xid", - "wasmparser 0.219.1", + "wasmparser 0.223.0", ] [[package]] diff --git a/RELEASES.md b/RELEASES.md index c4b36ed988b..d8d284ca1fa 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -359,7 +359,7 @@ Language - [`addr_of(_mut)!` macros and the newly stabilized `&raw (const|mut)` are now safe to use with all static items](https://github.com/rust-lang/rust/pull/125834) - [size_of_val_raw: for length 0 this is safe to call](https://github.com/rust-lang/rust/pull/126152/) - [Reorder trait bound modifiers *after* `for<...>` binder in trait bounds](https://github.com/rust-lang/rust/pull/127054/) -- [Stabilize opaque type precise capturing (RFC 3617)](https://github.com/rust-lang/rust/pull/127672) +- [Stabilize `+ use<'lt>` opaque type precise capturing (RFC 3617)](https://github.com/rust-lang/rust/pull/127672) - [Stabilize `&raw const` and `&raw mut` operators (RFC 2582)](https://github.com/rust-lang/rust/pull/127679) - [Stabilize unsafe extern blocks (RFC 3484)](https://github.com/rust-lang/rust/pull/127921) - [Stabilize nested field access in `offset_of!`](https://github.com/rust-lang/rust/pull/128284) diff --git a/compiler/rustc_ast/src/entry.rs b/compiler/rustc_ast/src/entry.rs index ab1413d6080..12cbb3b2a15 100644 --- a/compiler/rustc_ast/src/entry.rs +++ b/compiler/rustc_ast/src/entry.rs @@ -18,12 +18,6 @@ pub enum EntryPointType { /// fn main() {} /// ``` RustcMainAttr, - /// This is a function with the `#[start]` attribute. - /// ```ignore (clashes with test entrypoint) - /// #[start] - /// fn main() {} - /// ``` - Start, /// This function is **not** an entrypoint but simply named `main` (not at the root). /// This is only used for diagnostics. /// ``` @@ -40,9 +34,7 @@ pub fn entry_point_type( at_root: bool, name: Option<Symbol>, ) -> EntryPointType { - if attr::contains_name(attrs, sym::start) { - EntryPointType::Start - } else if attr::contains_name(attrs, sym::rustc_main) { + if attr::contains_name(attrs, sym::rustc_main) { EntryPointType::RustcMainAttr } else if let Some(name) = name && name == sym::main diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs index 266e77c0e02..f9fe4938ca8 100644 --- a/compiler/rustc_ast_lowering/src/delegation.rs +++ b/compiler/rustc_ast_lowering/src/delegation.rs @@ -72,7 +72,7 @@ impl<'hir> LoweringContext<'_, 'hir> { if let Some(local_sig_id) = def_id.as_local() { // The value may be missing due to recursive delegation. // Error will be emitted later during HIR ty lowering. - self.resolver.delegation_fn_sigs.get(&local_sig_id).map_or(false, |sig| sig.has_self) + self.resolver.delegation_fn_sigs.get(&local_sig_id).is_some_and(|sig| sig.has_self) } else { match self.tcx.def_kind(def_id) { DefKind::Fn => false, diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a76ca6772e5..f31e2c65c79 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -2159,7 +2159,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let path = hir::ExprKind::Path(hir::QPath::TypeRelative( self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))), self.arena.alloc(hir::PathSegment::new( - Ident::new(name, span), + Ident::new(name, self.lower_span(span)), self.next_id(), Res::Err, )), diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 29d4fb9ef25..9cfdbc47495 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -78,24 +78,31 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { // Make sure that the DepNode of some node coincides with the HirId // owner of that node. - if cfg!(debug_assertions) && hir_id.owner != self.owner { - span_bug!( - span, - "inconsistent HirId at `{:?}` for `{:?}`: \ + if cfg!(debug_assertions) { + if hir_id.owner != self.owner { + span_bug!( + span, + "inconsistent HirId at `{:?}` for `{node:?}`: \ current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", - self.tcx.sess.source_map().span_to_diagnostic_string(span), - node, - self.tcx - .definitions_untracked() - .def_path(self.owner.def_id) - .to_string_no_crate_verbose(), - self.owner, - self.tcx - .definitions_untracked() - .def_path(hir_id.owner.def_id) - .to_string_no_crate_verbose(), - hir_id.owner, - ) + self.tcx.sess.source_map().span_to_diagnostic_string(span), + self.tcx + .definitions_untracked() + .def_path(self.owner.def_id) + .to_string_no_crate_verbose(), + self.owner, + self.tcx + .definitions_untracked() + .def_path(hir_id.owner.def_id) + .to_string_no_crate_verbose(), + hir_id.owner, + ) + } + if self.tcx.sess.opts.incremental.is_some() + && span.parent().is_none() + && !span.is_dummy() + { + span_bug!(span, "span without a parent: {:#?}, {node:?}", span.data()) + } } self.nodes[hir_id.local_id] = ParentedNode { parent: self.parent_node, node }; diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 61d7da429f8..74870d74150 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1092,6 +1092,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // this as a special case. return self.lower_fn_body(decl, |this| { if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) { + let span = this.lower_span(span); let empty_block = hir::Block { hir_id: this.next_id(), stmts: &[], diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index abd314ae74c..3c78ed0497d 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -375,24 +375,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { expr: &Expr, allow_paths: bool, ) -> &'hir hir::PatExpr<'hir> { + let span = self.lower_span(expr.span); let err = |guar| hir::PatExprKind::Lit { - lit: self.arena.alloc(respan(self.lower_span(expr.span), LitKind::Err(guar))), + lit: self.arena.alloc(respan(span, LitKind::Err(guar))), negated: false, }; let kind = match &expr.kind { ExprKind::Lit(lit) => { - hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: false } + hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false } } ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)), ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit { - lit: self.arena.alloc(respan( - self.lower_span(expr.span), - LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked), - )), + lit: self + .arena + .alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))), negated: false, }, ExprKind::Err(guar) => err(*guar), - ExprKind::Dummy => span_bug!(expr.span, "lowered ExprKind::Dummy"), + ExprKind::Dummy => span_bug!(span, "lowered ExprKind::Dummy"), ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath( expr.id, qself, @@ -403,21 +403,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { None, )), ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => { - hir::PatExprKind::Lit { lit: self.lower_lit(lit, expr.span), negated: true } + hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true } } _ => { let pattern_from_macro = expr.is_approximately_pattern(); let guar = self.dcx().emit_err(ArbitraryExpressionInPattern { - span: expr.span, + span, pattern_from_macro_note: pattern_from_macro, }); err(guar) } }; - self.arena.alloc(hir::PatExpr { - hir_id: self.lower_node_id(expr.id), - span: expr.span, - kind, - }) + self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind }) } } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 94746212138..80b99f94485 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -83,7 +83,7 @@ impl<'a> PostExpansionVisitor<'a> { feature_err_issue(&self.sess, feature, span, GateIssue::Language, explain).emit(); } Err(abi::AbiDisabled::Unrecognized) => { - if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) { + if self.sess.opts.pretty.is_none_or(|ppm| ppm.needs_hir()) { self.sess.dcx().span_delayed_bug( span, format!( @@ -230,18 +230,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } } - ast::ItemKind::Fn(..) => { - if attr::contains_name(&i.attrs, sym::start) { - gate!( - &self, - start, - i.span, - "`#[start]` functions are experimental and their signature may change \ - over time" - ); - } - } - ast::ItemKind::Struct(..) | ast::ItemKind::Enum(..) | ast::ItemKind::Union(..) => { for attr in attr::filter_by_name(&i.attrs, sym::repr) { for item in attr.meta_item_list().unwrap_or_else(ThinVec::new) { diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 124f0aa3eff..28c381160b8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -166,7 +166,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &impl AttributeExt) -> Vec<ReprAttr // the `check_mod_attrs` pass, but this pass doesn't always run // (e.g. if we only pretty-print the source), so we have to gate // the `span_delayed_bug` call as follows: - if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) { + if sess.opts.pretty.is_none_or(|pp| pp.needs_analysis()) { dcx.span_delayed_bug(item.span(), "unrecognized representation hint"); } } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index da59f9f9ebd..d020244bf55 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -39,7 +39,9 @@ use rustc_trait_selection::error_reporting::traits::FindExprBySpan; use rustc_trait_selection::error_reporting::traits::call_kind::CallKind; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; +use rustc_trait_selection::traits::{ + Obligation, ObligationCause, ObligationCtxt, supertrait_def_ids, +}; use tracing::{debug, instrument}; use super::explain_borrow::{BorrowExplanation, LaterUseKind}; @@ -658,8 +660,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { clause.as_trait_clause().is_some_and(|tc| { tc.self_ty().skip_binder().is_param(param.index) && tc.polarity() == ty::PredicatePolarity::Positive - && tcx - .supertrait_def_ids(tc.def_id()) + && supertrait_def_ids(tcx, tc.def_id()) .flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order()) .any(|item| item.fn_has_self_parameter) }) @@ -2480,7 +2481,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // To support cases like `|| { v.call(|this| v.get()) }` // FIXME: actually support such cases (need to figure out how to move from the // capture place to original local). - && self.res.as_ref().map_or(true, |(prev_res, _)| prev_res.span.contains(ex.span)) + && self.res.as_ref().is_none_or(|(prev_res, _)| prev_res.span.contains(ex.span)) { self.res = Some((ex, closure)); } diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 5c0c1d0eb86..2656e0bb6a4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -131,10 +131,10 @@ impl<'tcx> BorrowExplanation<'tcx> { && let Ok(pat) = tcx.sess.source_map().span_to_snippet(pat.span) { suggest_rewrite_if_let(tcx, expr, &pat, init, conseq, alt, err); - } else if path_span.map_or(true, |path_span| path_span == var_or_use_span) { + } else if path_span.is_none_or(|path_span| path_span == var_or_use_span) { // We can use `var_or_use_span` if either `path_span` is not present, or both // spans are the same. - if borrow_span.map_or(true, |sp| !sp.overlaps(var_or_use_span)) { + if borrow_span.is_none_or(|sp| !sp.overlaps(var_or_use_span)) { err.span_label( var_or_use_span, format!("{borrow_desc}borrow later {message}"), diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index c6e6d962ce5..91dc76f597a 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -829,6 +829,7 @@ use self::ReadOrWrite::{Activation, Read, Reservation, Write}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum ArtificialField { + ArrayLength, FakeBorrow, } @@ -1338,11 +1339,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ); } - &Rvalue::Discriminant(place) => { + &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => { + let af = match *rvalue { + Rvalue::Len(..) => Some(ArtificialField::ArrayLength), + Rvalue::Discriminant(..) => None, + _ => unreachable!(), + }; self.access_place( location, (place, span), - (Shallow(None), Read(ReadKind::Copy)), + (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, state, ); diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 560b8c0349a..679e111caa9 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -203,7 +203,8 @@ fn place_components_conflict<'tcx>( let base_ty = base.ty(body, tcx).ty; match (elem, base_ty.kind(), access) { - (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => { + (_, _, Shallow(Some(ArtificialField::ArrayLength))) + | (_, _, Shallow(Some(ArtificialField::FakeBorrow))) => { // The array length is like additional fields on the // type; it does not overlap any existing data there. // Furthermore, if cannot actually be a prefix of any diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 0ad91ae51a3..cbcfab1dc3e 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -300,11 +300,16 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { self.consume_operand(location, op); } - &Rvalue::Discriminant(place) => { + &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => { + let af = match rvalue { + Rvalue::Len(..) => Some(ArtificialField::ArrayLength), + Rvalue::Discriminant(..) => None, + _ => unreachable!(), + }; self.access_place( location, place, - (Shallow(None), Read(ReadKind::Copy)), + (Shallow(af), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, ); } diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs index 3903c45fda5..bffd9f38334 100644 --- a/compiler/rustc_borrowck/src/type_check/canonical.rs +++ b/compiler/rustc_borrowck/src/type_check/canonical.rs @@ -185,7 +185,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { CustomTypeOp::new( |ocx| { let structurally_normalize = |ty| { - ocx.structurally_normalize( + ocx.structurally_normalize_ty( &ObligationCause::misc( location.to_locations().span(body), body.source.def_id().expect_local(), @@ -230,7 +230,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { ConstraintCategory::Boring, CustomTypeOp::new( |ocx| { - ocx.structurally_normalize( + ocx.structurally_normalize_ty( &ObligationCause::misc( location.to_locations().span(body), body.source.def_id().expect_local(), diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index eca8a688ff4..e0196d55f20 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2235,6 +2235,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { Rvalue::RawPtr(..) | Rvalue::ThreadLocalRef(..) + | Rvalue::Len(..) | Rvalue::Discriminant(..) | Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {} } @@ -2250,6 +2251,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::Repeat(..) | Rvalue::Ref(..) | Rvalue::RawPtr(..) + | Rvalue::Len(..) | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) | Rvalue::BinaryOp(..) diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 6071d36f8eb..0918403b855 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -16,6 +16,7 @@ #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustdoc_internals)] +#![feature(string_from_utf8_lossy_owned)] #![feature(try_blocks)] #![warn(unreachable_pub)] // tidy-alphabetical-end diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 123b96f6bca..d163da3ddea 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -13,7 +13,7 @@ use rustc_expand::base::{ use rustc_expand::module::DirOwnership; use rustc_lint_defs::BuiltinLintDiag; use rustc_parse::parser::{ForceCollect, Parser}; -use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal}; +use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error}; use rustc_session::lint::builtin::INCOMPLETE_INCLUDE; use rustc_span::source_map::SourceMap; use rustc_span::{Pos, Span, Symbol}; @@ -209,9 +209,10 @@ pub(crate) fn expand_include_str( let interned_src = Symbol::intern(src); MacEager::expr(cx.expr_str(cx.with_def_site_ctxt(bsp), interned_src)) } - Err(_) => { - let guar = cx.dcx().span_err(sp, format!("`{path}` wasn't a utf-8 file")); - DummyResult::any(sp, guar) + Err(utf8err) => { + let mut err = cx.dcx().struct_span_err(sp, format!("`{path}` wasn't a utf-8 file")); + utf8_error(cx.source_map(), path.as_str(), None, &mut err, utf8err, &bytes[..]); + DummyResult::any(sp, err.emit()) } }, Err(dummy) => dummy, @@ -273,7 +274,7 @@ fn load_binary_file( .and_then(|path| path.into_os_string().into_string().ok()); if let Some(new_path) = new_path { - err.span_suggestion( + err.span_suggestion_verbose( path_span, "there is a file with the same name in a different directory", format!("\"{}\"", new_path.replace('\\', "/").escape_debug()), diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 46446598943..31b068bd33d 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -204,11 +204,11 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { ast::mut_visit::walk_item(self, item); self.depth -= 1; - // Remove any #[rustc_main] or #[start] from the AST so it doesn't + // Remove any #[rustc_main] from the AST so it doesn't // clash with the one we're going to add, but mark it as // #[allow(dead_code)] to avoid printing warnings. match entry_point_type(&item, self.depth == 0) { - EntryPointType::MainNamed | EntryPointType::RustcMainAttr | EntryPointType::Start => { + EntryPointType::MainNamed | EntryPointType::RustcMainAttr => { let allow_dead_code = attr::mk_attr_nested_word( &self.sess.psess.attr_id_generator, ast::AttrStyle::Outer, @@ -217,8 +217,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> { sym::dead_code, self.def_site, ); - item.attrs - .retain(|attr| !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start)); + item.attrs.retain(|attr| !attr.has_name(sym::rustc_main)); item.attrs.push(allow_dead_code); } EntryPointType::None | EntryPointType::OtherMain => {} diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index e4c3dd708fd..9c6aad3490d 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-01-10" +channel = "nightly-2025-01-20" components = ["rust-src", "rustc-dev", "llvm-tools"] profile = "minimal" diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh index e569da90cf7..41aa011e805 100755 --- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh @@ -176,12 +176,11 @@ diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-supp index 9607ff02f96..b7d97caf9a2 100644 --- a/src/tools/run-make-support/src/external_deps/rustdoc.rs +++ b/src/tools/run-make-support/src/external_deps/rustdoc.rs -@@ -34,8 +34,6 @@ pub fn bare() -> Self { +@@ -34,7 +34,6 @@ pub fn bare() -> Self { #[track_caller] pub fn new() -> Self { let mut cmd = setup_common(); -- let target_rpath_dir = env_var_os("TARGET_RPATH_DIR"); -- cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy())); +- cmd.arg("-L").arg(env_var_os("TARGET_RPATH_DIR")); Self { cmd } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 956a024fa4d..34066eb83fc 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -828,6 +828,12 @@ fn codegen_stmt<'tcx>( fx.bcx.ins().nop(); } } + Rvalue::Len(place) => { + let place = codegen_place(fx, place); + let usize_layout = fx.layout_of(fx.tcx.types.usize); + let len = codegen_array_len(fx, place); + lval.write_cvalue(fx, CValue::by_val(len, usize_layout)); + } Rvalue::ShallowInitBox(ref operand, content_ty) => { let content_ty = fx.monomorphize(content_ty); let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty)); diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index fe578e44770..7d5592daac1 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -333,9 +333,17 @@ fn make_module(sess: &Session, name: String) -> UnwindModule<ObjectModule> { let mut builder = ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap(); + + // Disable function sections by default on MSVC as it causes significant slowdowns with link.exe. + // Maybe link.exe has exponential behavior when there are many sections with the same name? Also + // explicitly disable it on MinGW as rustc already disables it by default on MinGW and as such + // isn't tested. If rustc enables it in the future on MinGW, we can re-enable it too once it has + // been on MinGW. + let default_function_sections = sess.target.function_sections && !sess.target.is_like_windows; builder.per_function_section( - sess.opts.unstable_opts.function_sections.unwrap_or(sess.target.function_sections), + sess.opts.unstable_opts.function_sections.unwrap_or(default_function_sections), ); + UnwindModule::new(ObjectModule::new(builder), true) } diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 2e5813556aa..26f14532b45 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1,4 +1,5 @@ //! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, +//! functions marked with the `#[rustc_intrinsic]` attribute //! and LLVM intrinsics that have symbol names starting with `llvm.`. macro_rules! intrinsic_args { diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index e6bf0d5b47e..f6843496895 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -1,7 +1,7 @@ use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use rustc_hir::LangItem; use rustc_middle::ty::{AssocKind, GenericArg}; -use rustc_session::config::{EntryFnType, sigpipe}; +use rustc_session::config::EntryFnType; use rustc_span::{DUMMY_SP, Ident}; use crate::prelude::*; @@ -14,10 +14,9 @@ pub(crate) fn maybe_create_entry_wrapper( is_jit: bool, is_primary_cgu: bool, ) { - let (main_def_id, (is_main_fn, sigpipe)) = match tcx.entry_fn(()) { + let (main_def_id, sigpipe) = match tcx.entry_fn(()) { Some((def_id, entry_ty)) => (def_id, match entry_ty { - EntryFnType::Main { sigpipe } => (true, sigpipe), - EntryFnType::Start => (false, sigpipe::DEFAULT), + EntryFnType::Main { sigpipe } => sigpipe, }), None => return, }; @@ -31,14 +30,13 @@ pub(crate) fn maybe_create_entry_wrapper( return; } - create_entry_fn(tcx, module, main_def_id, is_jit, is_main_fn, sigpipe); + create_entry_fn(tcx, module, main_def_id, is_jit, sigpipe); fn create_entry_fn( tcx: TyCtxt<'_>, m: &mut dyn Module, rust_main_def_id: DefId, ignore_lang_start_wrapper: bool, - is_main_fn: bool, sigpipe: u8, ) { let main_ret_ty = tcx.fn_sig(rust_main_def_id).no_bound_vars().unwrap().output(); @@ -94,8 +92,8 @@ pub(crate) fn maybe_create_entry_wrapper( let main_func_ref = m.declare_func_in_func(main_func_id, &mut bcx.func); - let result = if is_main_fn && ignore_lang_start_wrapper { - // regular main fn, but ignoring #[lang = "start"] as we are running in the jit + let result = if ignore_lang_start_wrapper { + // ignoring #[lang = "start"] as we are running in the jit // FIXME set program arguments somehow let call_inst = bcx.ins().call(main_func_ref, &[]); let call_results = bcx.func.dfg.inst_results(call_inst).to_owned(); @@ -133,7 +131,8 @@ pub(crate) fn maybe_create_entry_wrapper( types::I64 => bcx.ins().sextend(types::I64, res), _ => unimplemented!("16bit systems are not yet supported"), } - } else if is_main_fn { + } else { + // Regular main fn invoked via start lang item. let start_def_id = tcx.require_lang_item(LangItem::Start, None); let start_instance = Instance::expect_resolve( tcx, @@ -150,10 +149,6 @@ pub(crate) fn maybe_create_entry_wrapper( let call_inst = bcx.ins().call(func_ref, &[main_val, arg_argc, arg_argv, arg_sigpipe]); bcx.inst_results(call_inst)[0] - } else { - // using user-defined start fn - let call_inst = bcx.ins().call(main_func_ref, &[arg_argc, arg_argv]); - bcx.inst_results(call_inst)[0] }; bcx.ins().return_(&[result]); diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs index 7cc7336612c..0e790a4befc 100644 --- a/compiler/rustc_codegen_gcc/build_system/src/test.rs +++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs @@ -426,19 +426,6 @@ fn std_tests(env: &Env, args: &TestArg) -> Result<(), String> { run_command_with_env(&command, None, Some(env))?; maybe_run_command_in_vm(&[&cargo_target_dir.join("track-caller-attribute")], env, args)?; - // FIXME: create a function "display_if_not_quiet" or something along the line. - println!("[AOT] mod_bench"); - let mut command = args.config_info.rustc_command_vec(); - command.extend_from_slice(&[ - &"example/mod_bench.rs", - &"--crate-type", - &"bin", - &"--target", - &args.config_info.target_triple, - ]); - run_command_with_env(&command, None, Some(env))?; - // FIXME: the compiled binary is not run. - Ok(()) } @@ -696,19 +683,6 @@ fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> { Ok(()) } -// echo "[BENCH COMPILE] mod_bench" -// -// COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline" -// COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o $cargo_target_dir/mod_bench_llvm_0 -Cpanic=abort" -// COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o $cargo_target_dir/mod_bench_llvm_1 -Cpanic=abort" -// COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o $cargo_target_dir/mod_bench_llvm_2 -Cpanic=abort" -// COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o $cargo_target_dir/mod_bench_llvm_3 -Cpanic=abort" -// -// Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow -// hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3" -// echo "[BENCH RUN] mod_bench" -// hyperfine --runs ${RUN_RUNS:-10} $cargo_target_dir/mod_bench{,_inline} $cargo_target_dir/mod_bench_llvm_* - fn extended_rand_tests(env: &Env, args: &TestArg) -> Result<(), String> { if !args.is_using_gcc_master_branch() { println!("Not using GCC master branch. Skipping `extended_rand_tests`."); diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs index 6ed8b9157f2..9a0b46d5b22 100644 --- a/compiler/rustc_codegen_gcc/example/alloc_example.rs +++ b/compiler/rustc_codegen_gcc/example/alloc_example.rs @@ -1,5 +1,6 @@ -#![feature(start, core_intrinsics, alloc_error_handler, lang_items)] +#![feature(core_intrinsics, alloc_error_handler, lang_items)] #![no_std] +#![no_main] #![allow(internal_features)] extern crate alloc; @@ -37,8 +38,8 @@ unsafe extern "C" fn _Unwind_Resume() { core::intrinsics::unreachable(); } -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { let world: Box<&str> = Box::new("Hello World!\0"); unsafe { puts(*world as *const str as *const u8); diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs index 1d51e0a1856..4cbe66c5e4c 100644 --- a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs +++ b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs @@ -1,7 +1,7 @@ // Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs #![feature( - no_core, unboxed_closures, start, lang_items, never_type, linkage, + no_core, unboxed_closures, lang_items, never_type, linkage, extern_types, thread_local )] #![no_core] diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs deleted file mode 100644 index e8a9cade747..00000000000 --- a/compiler/rustc_codegen_gcc/example/mod_bench.rs +++ /dev/null @@ -1,36 +0,0 @@ -#![feature(start, core_intrinsics, lang_items)] -#![no_std] -#![allow(internal_features)] - -#[link(name = "c")] -extern "C" {} - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! { - core::intrinsics::abort(); -} - -#[lang="eh_personality"] -fn eh_personality(){} - -// Required for rustc_codegen_llvm -#[no_mangle] -unsafe extern "C" fn _Unwind_Resume() { - core::intrinsics::unreachable(); -} - -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - for i in 2..100_000_000 { - black_box((i + 1) % i); - } - - 0 -} - -#[inline(never)] -fn black_box(i: u32) { - if i != 1 { - core::intrinsics::abort(); - } -} diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index f43743fc2a4..bd5d6ba387c 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -64,6 +64,11 @@ impl<'gcc, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { if type_is_pointer(typ) { self.context.new_null(typ) } else { self.const_int(typ, 0) } } + fn is_undef(&self, _val: RValue<'gcc>) -> bool { + // FIXME: actually check for undef + false + } + fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> { let local = self.current_func.borrow().expect("func").new_local(None, typ, "undefined"); if typ.is_struct().is_some() { diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index c81c53359fd..30732c74eb3 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -513,7 +513,6 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } else { // If the symbol already exists, it is an error: for example, the user wrote // #[no_mangle] extern "C" fn main(..) {..} - // instead of #[start] None } } diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs index d3aeb7f3bde..4b84b1dbfd3 100644 --- a/compiler/rustc_codegen_gcc/src/debuginfo.rs +++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs @@ -113,15 +113,15 @@ fn make_mir_scope<'gcc, 'tcx>( let scope_data = &mir.source_scopes[scope]; let parent_scope = if let Some(parent) = scope_data.parent_scope { make_mir_scope(cx, _instance, mir, variables, debug_context, instantiated, parent); - debug_context.scopes[parent].unwrap() + debug_context.scopes[parent] } else { // The root is the function itself. let file = cx.sess().source_map().lookup_source_file(mir.span.lo()); - debug_context.scopes[scope] = Some(DebugScope { + debug_context.scopes[scope] = DebugScope { file_start_pos: file.start_pos, file_end_pos: file.end_position(), - ..debug_context.scopes[scope].unwrap() - }); + ..debug_context.scopes[scope] + }; instantiated.insert(scope); return; }; @@ -130,7 +130,7 @@ fn make_mir_scope<'gcc, 'tcx>( if !vars.contains(scope) && scope_data.inlined.is_none() { // Do not create a DIScope if there are no variables defined in this // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. - debug_context.scopes[scope] = Some(parent_scope); + debug_context.scopes[scope] = parent_scope; instantiated.insert(scope); return; } @@ -157,12 +157,12 @@ fn make_mir_scope<'gcc, 'tcx>( // TODO(tempdragon): dbg_scope: Add support for scope extension here. inlined_at.or(p_inlined_at); - debug_context.scopes[scope] = Some(DebugScope { + debug_context.scopes[scope] = DebugScope { dbg_scope, inlined_at, file_start_pos: loc.file.start_pos, file_end_pos: loc.file.end_position(), - }); + }; instantiated.insert(scope); } @@ -232,12 +232,12 @@ impl<'gcc, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { } // Initialize fn debug context (including scopes). - let empty_scope = Some(DebugScope { + let empty_scope = DebugScope { dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)), inlined_at: None, file_start_pos: BytePos(0), file_end_pos: BytePos(0), - }); + }; let mut fn_debug_context = FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, mir.source_scopes.as_slice()), inlined_function_scopes: Default::default(), diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs index 696197d7377..385e41a6881 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs @@ -3,11 +3,12 @@ // Run-time: // status: signal -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -49,7 +50,7 @@ fn test_fail() -> ! { unsafe { intrinsics::abort() }; } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { test_fail(); } diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs index 714cd6c0f38..6c66a930e07 100644 --- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs +++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs @@ -3,11 +3,12 @@ // Run-time: // status: signal -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -50,8 +51,8 @@ fn fail() -> i32 { 0 } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { fail(); 0 } diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs index c3c08c29c6d..e18a4ced6bc 100644 --- a/compiler/rustc_codegen_gcc/tests/run/array.rs +++ b/compiler/rustc_codegen_gcc/tests/run/array.rs @@ -7,10 +7,11 @@ // 5 // 10 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -28,8 +29,8 @@ fn make_array() -> [u8; 3] { [42, 10, 5] } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let array = [42, 7, 5]; let array2 = make_array(); unsafe { diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs index 2a47f0c2966..4d414c577a6 100644 --- a/compiler/rustc_codegen_gcc/tests/run/assign.rs +++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs @@ -6,10 +6,11 @@ // 10 #![allow(internal_features, unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -142,8 +143,8 @@ fn inc(num: isize) -> isize { } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { argc = inc(argc); unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc); diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs index 46c47bc54ed..c7a236f74f9 100644 --- a/compiler/rustc_codegen_gcc/tests/run/closure.rs +++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs @@ -8,10 +8,11 @@ // Int argument: 2 // Both args: 11 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -22,8 +23,8 @@ mod libc { } } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let string = "Arg: %d\n\0"; let mut closure = || { unsafe { diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs index 039ef94eaa7..b02359702ed 100644 --- a/compiler/rustc_codegen_gcc/tests/run/condition.rs +++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs @@ -5,10 +5,11 @@ // stdout: true // 1 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -19,8 +20,8 @@ mod libc { } } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { if argc == 1 { libc::printf(b"true\n\0" as *const u8 as *const i8); diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs index e66a859ad69..042e44080c5 100644 --- a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs +++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs @@ -3,11 +3,12 @@ // Run-time: // status: 0 -#![feature(auto_traits, lang_items, no_core, start)] +#![feature(auto_traits, lang_items, no_core)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {} * Code */ -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { 0 } diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs index bf1cbeef302..9a7c91c0adb 100644 --- a/compiler/rustc_codegen_gcc/tests/run/exit.rs +++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs @@ -3,11 +3,12 @@ // Run-time: // status: 2 -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, intrinsics)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] mod libc { #[link(name = "c")] @@ -41,8 +42,8 @@ pub(crate) unsafe auto trait Freeze {} * Code */ -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { libc::exit(2); } diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs index be7a233efda..c50d2b0d710 100644 --- a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs +++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs @@ -3,11 +3,12 @@ // Run-time: // status: 1 -#![feature(auto_traits, lang_items, no_core, start)] +#![feature(auto_traits, lang_items, no_core)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -34,7 +35,7 @@ pub(crate) unsafe auto trait Freeze {} * Code */ -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { 1 } diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs index ed1bf72bb27..98b351e5044 100644 --- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs +++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs @@ -4,10 +4,11 @@ // status: 0 // stdout: 1 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -26,8 +27,8 @@ fn call_func(func: fn(i16) -> i8, param: i16) -> i8 { func(param) } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { let result = call_func(i16_as_i8, argc as i16) as isize; libc::printf(b"%ld\n\0" as *const u8 as *const i8, result); diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs index 3ae79338216..9be64f991ee 100644 --- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs +++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs @@ -8,10 +8,11 @@ // 11 #![allow(internal_features, unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs, track_caller)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -148,8 +149,8 @@ fn update_num(num: &mut isize) { *num = *num + 5; } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let mut test = test(argc); unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field); diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs index 0e44fc580b8..c92d3cc0b8f 100644 --- a/compiler/rustc_codegen_gcc/tests/run/operations.rs +++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs @@ -6,10 +6,11 @@ // 10 #![allow(internal_features, unused_attributes)] -#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types, rustc_attrs)] +#![feature(auto_traits, lang_items, no_core, intrinsics, arbitrary_self_types, rustc_attrs)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -231,8 +232,8 @@ pub fn panic_const_mul_overflow() -> ! { * Code */ -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc); libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc); diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs index 2b8812ad51c..0ba49e7187f 100644 --- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs +++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs @@ -4,10 +4,11 @@ // status: 0 // stdout: 1 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -24,8 +25,8 @@ fn make_array() -> [u8; 3] { [42, 10, 5] } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { let ptr = ONE as *mut usize; let value = ptr as usize; diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs index f2a5a2e4384..3cc1e274001 100644 --- a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs +++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs @@ -6,11 +6,12 @@ // 10 // 42 -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, intrinsics)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] #[lang = "copy"] pub unsafe trait Copy {} @@ -61,8 +62,8 @@ fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u3 ) } -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42); unsafe { libc::printf(b"%d\n\0" as *const u8 as *const i8, c); diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs index fba93fc1554..825fcb8a081 100644 --- a/compiler/rustc_codegen_gcc/tests/run/slice.rs +++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs @@ -4,10 +4,11 @@ // status: 0 // stdout: 5 -#![feature(no_core, start)] +#![feature(no_core)] #![no_std] #![no_core] +#![no_main] extern crate mini_core; @@ -26,8 +27,8 @@ fn index_slice(s: &[u32]) -> u32 { } } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let array = [42, 7, 5]; unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array)); diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs index a17ea2a4893..80c8782c4b1 100644 --- a/compiler/rustc_codegen_gcc/tests/run/static.rs +++ b/compiler/rustc_codegen_gcc/tests/run/static.rs @@ -9,11 +9,12 @@ // 12 // 1 -#![feature(auto_traits, lang_items, no_core, start, intrinsics, rustc_attrs)] +#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -98,8 +99,8 @@ static mut WITH_REF: WithRef = WithRef { refe: unsafe { &TEST }, }; -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT); libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field); diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs index d6455667400..59b8f358863 100644 --- a/compiler/rustc_codegen_gcc/tests/run/structs.rs +++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs @@ -5,11 +5,12 @@ // stdout: 1 // 2 -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, intrinsics)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -55,8 +56,8 @@ fn one() -> isize { 1 } -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let test = Test { field: one(), }; diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs index 8a7d85ae867..ed60a56a68c 100644 --- a/compiler/rustc_codegen_gcc/tests/run/tuple.rs +++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs @@ -4,11 +4,12 @@ // status: 0 // stdout: 3 -#![feature(auto_traits, lang_items, no_core, start, intrinsics)] +#![feature(auto_traits, lang_items, no_core, intrinsics)] #![allow(internal_features)] #![no_std] #![no_core] +#![no_main] /* * Core @@ -42,8 +43,8 @@ mod libc { * Code */ -#[start] -fn main(mut argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { let test: (isize, isize, isize) = (3, 1, 4); unsafe { libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0); diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index c44d1a5e5c2..94f21ac5f57 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -9,6 +9,8 @@ test = false [dependencies] # tidy-alphabetical-start bitflags = "2.4.1" +# To avoid duplicate dependencies, this should match the version of gimli used +# by `rustc_codegen_ssa` via its `thorin-dwp` dependency. gimli = "0.30" itertools = "0.12" libc = "0.2" diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 509b24dd703..4706744f353 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -769,12 +769,9 @@ pub(crate) unsafe fn codegen( } } - // Two things to note: - // - If object files are just LLVM bitcode we write bitcode, copy it to - // the .o file, and delete the bitcode if it wasn't otherwise - // requested. - // - If we don't have the integrated assembler then we need to emit - // asm from LLVM and use `gcc` to create the object file. + // Note that if object files are just LLVM bitcode we write bitcode, + // copy it to the .o file, and delete the bitcode if it wasn't + // otherwise requested. let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name); let bc_summary_out = diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index adfe8aeb5c5..b4e9b9f44f4 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -126,6 +126,10 @@ impl<'ll, 'tcx> ConstCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMGetUndef(t) } } + fn is_undef(&self, v: &'ll Value) -> bool { + unsafe { llvm::LLVMIsUndef(v) == True } + } + fn const_poison(&self, t: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMGetPoison(t) } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 65345751842..91283a5944e 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -751,7 +751,6 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } else { // If the symbol already exists, it is an error: for example, the user wrote // #[no_mangle] extern "C" fn main(..) {..} - // instead of #[start] None } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index e545ce386ed..11eb9651af6 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::{Body, SourceScope}; use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; use rustc_middle::ty::{self, Instance}; use rustc_session::config::DebugInfo; -use rustc_span::{BytePos, hygiene}; +use rustc_span::{BytePos, DUMMY_SP, hygiene}; use super::metadata::file_metadata; use super::utils::DIB; @@ -85,23 +85,15 @@ fn make_mir_scope<'ll, 'tcx>( discriminators, parent, ); - if let Some(parent_scope) = debug_context.scopes[parent] { - parent_scope - } else { - // If the parent scope could not be represented then no children - // can be either. - debug_context.scopes[scope] = None; - instantiated.insert(scope); - return; - } + debug_context.scopes[parent] } else { // The root is the function itself. let file = cx.sess().source_map().lookup_source_file(mir.span.lo()); - debug_context.scopes[scope] = Some(DebugScope { + debug_context.scopes[scope] = DebugScope { file_start_pos: file.start_pos, file_end_pos: file.end_position(), - ..debug_context.scopes[scope].unwrap() - }); + ..debug_context.scopes[scope] + }; instantiated.insert(scope); return; }; @@ -112,7 +104,7 @@ fn make_mir_scope<'ll, 'tcx>( { // Do not create a DIScope if there are no variables defined in this // MIR `SourceScope`, and it's not `inlined`, to avoid debuginfo bloat. - debug_context.scopes[scope] = Some(parent_scope); + debug_context.scopes[scope] = parent_scope; instantiated.insert(scope); return; } @@ -145,14 +137,7 @@ fn make_mir_scope<'ll, 'tcx>( }, }; - let mut debug_scope = Some(DebugScope { - dbg_scope, - inlined_at: parent_scope.inlined_at, - file_start_pos: loc.file.start_pos, - file_end_pos: loc.file.end_position(), - }); - - if let Some((_, callsite_span)) = scope_data.inlined { + let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { let callsite_span = hygiene::walk_chain_collapsed(callsite_span, mir.span); let callsite_scope = parent_scope.adjust_dbg_scope_for_span(cx, callsite_span); let loc = cx.dbg_loc(callsite_scope, parent_scope.inlined_at, callsite_span); @@ -175,29 +160,29 @@ fn make_mir_scope<'ll, 'tcx>( // Note further that we can't key this hashtable on the span itself, // because these spans could have distinct SyntaxContexts. We have // to key on exactly what we're giving to LLVM. - let inlined_at = match discriminators.entry(callsite_span.lo()) { + match discriminators.entry(callsite_span.lo()) { Entry::Occupied(mut o) => { *o.get_mut() += 1; + // NB: We have to emit *something* here or we'll fail LLVM IR verification + // in at least some circumstances (see issue #135322) so if the required + // discriminant cannot be encoded fall back to the dummy location. unsafe { llvm::LLVMRustDILocationCloneWithBaseDiscriminator(loc, *o.get()) } + .unwrap_or_else(|| { + cx.dbg_loc(callsite_scope, parent_scope.inlined_at, DUMMY_SP) + }) } Entry::Vacant(v) => { v.insert(0); - Some(loc) - } - }; - match inlined_at { - Some(inlined_at) => { - debug_scope.as_mut().unwrap().inlined_at = Some(inlined_at); - } - None => { - // LLVM has a maximum discriminator that it can encode (currently - // it uses 12 bits for 4096 possible values). If we exceed that - // there is little we can do but drop the debug info. - debug_scope = None; + loc } } - } + }); - debug_context.scopes[scope] = debug_scope; + debug_context.scopes[scope] = DebugScope { + dbg_scope, + inlined_at: inlined_at.or(parent_scope.inlined_at), + file_start_pos: loc.file.start_pos, + file_end_pos: loc.file.end_position(), + }; instantiated.insert(scope); } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 88e43e1c678..8d782a618fc 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -442,7 +442,7 @@ pub(crate) fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> // (or if there is no allocator argument). ty::Adt(def, args) if def.is_box() - && args.get(1).map_or(true, |arg| cx.layout_of(arg.expect_ty()).is_1zst()) => + && args.get(1).is_none_or(|arg| cx.layout_of(arg.expect_ty()).is_1zst()) => { build_pointer_or_reference_di_node(cx, t, t.expect_boxed_ty(), unique_type_id) } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 755f4816acf..e6778411365 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -295,12 +295,12 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { } // Initialize fn debug context (including scopes). - let empty_scope = Some(DebugScope { + let empty_scope = DebugScope { dbg_scope: self.dbg_scope_fn(instance, fn_abi, Some(llfn)), inlined_at: None, file_start_pos: BytePos(0), file_end_pos: BytePos(0), - }); + }; let mut fn_debug_context = FunctionDebugContext { scopes: IndexVec::from_elem(empty_scope, &mir.source_scopes), inlined_function_scopes: Default::default(), diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index ec6c84f6f25..009d15a932f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -741,8 +741,11 @@ pub mod debuginfo { pub type DIEnumerator = DIDescriptor; pub type DITemplateTypeParameter = DIDescriptor; - // These values **must** match with LLVMRustDIFlags!! bitflags! { + /// Must match the layout of `LLVMDIFlags` in the LLVM-C API. + /// + /// Each value declared here must also be covered by the static + /// assertions in `RustWrapper.cpp` used by `fromRust(LLVMDIFlags)`. #[repr(transparent)] #[derive(Clone, Copy, Default)] pub struct DIFlags: u32 { @@ -752,7 +755,7 @@ pub mod debuginfo { const FlagPublic = 3; const FlagFwdDecl = (1 << 2); const FlagAppleBlock = (1 << 3); - const FlagBlockByrefStruct = (1 << 4); + const FlagReservedBit4 = (1 << 4); const FlagVirtual = (1 << 5); const FlagArtificial = (1 << 6); const FlagExplicit = (1 << 7); @@ -763,10 +766,21 @@ pub mod debuginfo { const FlagStaticMember = (1 << 12); const FlagLValueReference = (1 << 13); const FlagRValueReference = (1 << 14); - const FlagExternalTypeRef = (1 << 15); + const FlagReserved = (1 << 15); + const FlagSingleInheritance = (1 << 16); + const FlagMultipleInheritance = (2 << 16); + const FlagVirtualInheritance = (3 << 16); const FlagIntroducedVirtual = (1 << 18); const FlagBitField = (1 << 19); const FlagNoReturn = (1 << 20); + // The bit at (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`. + const FlagTypePassByValue = (1 << 22); + const FlagTypePassByReference = (1 << 23); + const FlagEnumClass = (1 << 24); + const FlagThunk = (1 << 25); + const FlagNonTrivial = (1 << 26); + const FlagBigEndian = (1 << 27); + const FlagLittleEndian = (1 << 28); } } @@ -918,6 +932,7 @@ unsafe extern "C" { pub fn LLVMMetadataTypeInContext(C: &Context) -> &Type; // Operations on all values + pub fn LLVMIsUndef(Val: &Value) -> Bool; pub fn LLVMTypeOf(Val: &Value) -> &Type; pub fn LLVMGetValueName2(Val: &Value, Length: *mut size_t) -> *const c_char; pub fn LLVMSetValueName2(Val: &Value, Name: *const c_char, NameLen: size_t); diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 3254b5d38e7..b6b453d069e 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -59,5 +59,5 @@ default-features = false features = ["read_core", "elf", "macho", "pe", "xcoff", "unaligned", "archive", "write", "wasm"] [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = ["Win32_Globalization"] diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 484f467068a..a4c50dcc135 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -211,7 +211,7 @@ codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times - .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead + .help = did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point codegen_ssa_no_field = no field `{$name}` diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 544578b29f1..83724af604d 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -490,8 +490,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let ptr_ty = cx.type_ptr(); let (arg_argc, arg_argv) = get_argc_argv(&mut bx); - let (start_fn, start_ty, args, instance) = if let EntryFnType::Main { sigpipe } = entry_type - { + let EntryFnType::Main { sigpipe } = entry_type; + let (start_fn, start_ty, args, instance) = { let start_def_id = cx.tcx().require_lang_item(LangItem::Start, None); let start_instance = ty::Instance::expect_resolve( cx.tcx(), @@ -512,10 +512,6 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( vec![rust_main, arg_argc, arg_argv, arg_sigpipe], Some(start_instance), ) - } else { - debug!("using user-defined start fn"); - let start_ty = cx.type_func(&[isize_ty, ptr_ty], isize_ty); - (rust_main, start_ty, vec![arg_argc, arg_argv], None) }; let result = bx.call(start_ty, None, None, start_fn, &args, None, instance); @@ -530,7 +526,8 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -/// Obtain the `argc` and `argv` values to pass to the rust start function. +/// Obtain the `argc` and `argv` values to pass to the rust start function +/// (i.e., the "start" lang item). fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(bx: &mut Bx) -> (Bx::Value, Bx::Value) { if bx.cx().sess().target.os.contains("uefi") { // Params for UEFI diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 843a996d2bf..5924c8991ad 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -19,9 +19,7 @@ use crate::traits::*; pub struct FunctionDebugContext<'tcx, S, L> { /// Maps from source code to the corresponding debug info scope. - /// May be None if the backend is not capable of representing the scope for - /// some reason. - pub scopes: IndexVec<mir::SourceScope, Option<DebugScope<S, L>>>, + pub scopes: IndexVec<mir::SourceScope, DebugScope<S, L>>, /// Maps from an inlined function to its debug info declaration. pub inlined_function_scopes: FxHashMap<Instance<'tcx>, S>, @@ -232,7 +230,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &self, source_info: mir::SourceInfo, ) -> Option<(Bx::DIScope, Option<Bx::DILocation>, Span)> { - let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]?; + let scope = &self.debug_context.as_ref()?.scopes[source_info.scope]; let span = hygiene::walk_chain_collapsed(source_info.span, self.mir.span); Some((scope.adjust_dbg_scope_for_span(self.cx, span), scope.inlined_at, span)) } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 19101ec2d1b..9ca7d4f8f00 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -204,14 +204,30 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let alloc_align = alloc.inner().align; assert!(alloc_align >= layout.align.abi); + // Returns `None` when the value is partially undefined or any byte of it has provenance. + // Otherwise returns the value or (if the entire value is undef) returns an undef. let read_scalar = |start, size, s: abi::Scalar, ty| { + let range = alloc_range(start, size); match alloc.0.read_scalar( bx, - alloc_range(start, size), + range, /*read_provenance*/ matches!(s.primitive(), abi::Primitive::Pointer(_)), ) { - Ok(val) => bx.scalar_to_backend(val, s, ty), - Err(_) => bx.const_poison(ty), + Ok(val) => Some(bx.scalar_to_backend(val, s, ty)), + Err(_) => { + // We may have failed due to partial provenance or unexpected provenance, + // continue down the normal code path if so. + if alloc.0.provenance().range_empty(range, &bx.tcx()) + // Since `read_scalar` failed, but there were no relocations involved, the + // bytes must be partially or fully uninitialized. Thus we can now unwrap the + // information about the range of uninit bytes and check if it's the full range. + && alloc.0.init_mask().is_range_initialized(range).unwrap_err() == range + { + Some(bx.const_undef(ty)) + } else { + None + } + } } }; @@ -222,16 +238,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // check that walks over the type of `mplace` to make sure it is truly correct to treat this // like a `Scalar` (or `ScalarPair`). match layout.backend_repr { - BackendRepr::Scalar(s @ abi::Scalar::Initialized { .. }) => { + BackendRepr::Scalar(s) => { let size = s.size(bx); assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); - let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout)); - OperandRef { val: OperandValue::Immediate(val), layout } + if let Some(val) = read_scalar(offset, size, s, bx.immediate_backend_type(layout)) { + return OperandRef { val: OperandValue::Immediate(val), layout }; + } } - BackendRepr::ScalarPair( - a @ abi::Scalar::Initialized { .. }, - b @ abi::Scalar::Initialized { .. }, - ) => { + BackendRepr::ScalarPair(a, b) => { let (a_size, b_size) = (a.size(bx), b.size(bx)); let b_offset = (offset + a_size).align_to(b.align(bx).abi); assert!(b_offset.bytes() > 0); @@ -247,20 +261,21 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { b, bx.scalar_pair_element_backend_type(layout, 1, true), ); - OperandRef { val: OperandValue::Pair(a_val, b_val), layout } - } - _ if layout.is_zst() => OperandRef::zero_sized(layout), - _ => { - // Neither a scalar nor scalar pair. Load from a place - // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the - // same `ConstAllocation`? - let init = bx.const_data_from_alloc(alloc); - let base_addr = bx.static_addr_of(init, alloc_align, None); - - let llval = bx.const_ptr_byte_offset(base_addr, offset); - bx.load_operand(PlaceRef::new_sized(llval, layout)) + if let (Some(a_val), Some(b_val)) = (a_val, b_val) { + return OperandRef { val: OperandValue::Pair(a_val, b_val), layout }; + } } + _ if layout.is_zst() => return OperandRef::zero_sized(layout), + _ => {} } + // Neither a scalar nor scalar pair. Load from a place + // FIXME: should we cache `const_data_from_alloc` to avoid repeating this for the + // same `ConstAllocation`? + let init = bx.const_data_from_alloc(alloc); + let base_addr = bx.static_addr_of(init, alloc_align, None); + + let llval = bx.const_ptr_byte_offset(base_addr, offset); + bx.load_operand(PlaceRef::new_sized(llval, layout)) } /// Asserts that this operand refers to a scalar and returns diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 31793641d75..e775d219c7b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -8,11 +8,11 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_middle::{bug, mir, span_bug}; use rustc_session::config::OptLevel; use rustc_span::{DUMMY_SP, Span}; -use tracing::{debug, instrument}; +use tracing::{debug, instrument, trace}; -use super::FunctionCx; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; +use super::{FunctionCx, LocalRef}; use crate::common::IntPredicate; use crate::traits::*; use crate::{MemFlags, base}; @@ -93,6 +93,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } + // If `v` is an integer constant whose value is just a single byte repeated N times, + // emit a `memset` filling the entire `dest` with that byte. let try_init_all_same = |bx: &mut Bx, v| { let start = dest.val.llval; let size = bx.const_usize(dest.layout.size.bytes()); @@ -117,13 +119,33 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { false }; + trace!(?cg_elem.val); match cg_elem.val { OperandValue::Immediate(v) => { if try_init_all_same(bx, v) { return; } } - _ => (), + OperandValue::Pair(a, b) => { + let a_is_undef = bx.cx().is_undef(a); + match (a_is_undef, bx.cx().is_undef(b)) { + // Can happen for uninit unions + (true, true) => { + // FIXME: can we produce better output here? + } + (false, true) | (true, false) => { + let val = if a_is_undef { b } else { a }; + if try_init_all_same(bx, val) { + return; + } + } + (false, false) => { + // FIXME: if both are the same value, use try_init_all_same + } + } + } + OperandValue::ZeroSized => unreachable!("checked above"), + OperandValue::Ref(..) => {} } let count = self @@ -365,10 +387,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { use abi::Primitive::*; imm = bx.from_immediate(imm); - // When scalars are passed by value, there's no metadata recording their - // valid ranges. For example, `char`s are passed as just `i32`, with no - // way for LLVM to know that they're 0x10FFFF at most. Thus we assume - // the range of the input value too, not just the output range. + // If we have a scalar, we must already know its range. Either + // + // 1) It's a parameter with `range` parameter metadata, + // 2) It's something we `load`ed with `!range` metadata, or + // 3) After a transmute we `assume`d the range (see below). + // + // That said, last time we tried removing this, it didn't actually help + // the rustc-perf results, so might as well keep doing it + // <https://github.com/rust-lang/rust/pull/135610#issuecomment-2599275182> self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty); imm = match (from_scalar.primitive(), to_scalar.primitive()) { @@ -389,7 +416,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bx.bitcast(int_imm, to_backend_ty) } }; + + // This `assume` remains important for cases like (a conceptual) + // transmute::<u32, NonZeroU32>(x) == 0 + // since it's never passed to something with parameter metadata (especially + // after MIR inlining) so the only way to tell the backend about the + // constraint that the `transmute` introduced is to `assume` it. self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty); + imm = bx.to_immediate_scalar(imm, to_scalar); imm } @@ -411,31 +445,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { return; } - let abi::WrappingRange { start, end } = scalar.valid_range(self.cx); - - if start <= end { - if start > 0 { - let low = bx.const_uint_big(backend_ty, start); - let cmp = bx.icmp(IntPredicate::IntUGE, imm, low); - bx.assume(cmp); - } - - let type_max = scalar.size(self.cx).unsigned_int_max(); - if end < type_max { - let high = bx.const_uint_big(backend_ty, end); - let cmp = bx.icmp(IntPredicate::IntULE, imm, high); - bx.assume(cmp); - } - } else { - let low = bx.const_uint_big(backend_ty, start); - let cmp_low = bx.icmp(IntPredicate::IntUGE, imm, low); - - let high = bx.const_uint_big(backend_ty, end); - let cmp_high = bx.icmp(IntPredicate::IntULE, imm, high); - - let or = bx.or(cmp_low, cmp_high); - bx.assume(or); - } + let range = scalar.valid_range(self.cx); + bx.assume_integer_range(imm, backend_ty, range); } pub(crate) fn codegen_rvalue_unsized( @@ -607,6 +618,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_place_to_pointer(bx, place, mk_ptr) } + mir::Rvalue::Len(place) => { + let size = self.evaluate_array_len(bx, place); + OperandRef { + val: OperandValue::Immediate(size), + layout: bx.cx().layout_of(bx.tcx().types.usize), + } + } + mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs)) if let Some(op) = op_with_overflow.overflowing_to_wrapping() => { @@ -806,6 +825,24 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } + fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value { + // ZST are passed as operands and require special handling + // because codegen_place() panics if Local is operand. + if let Some(index) = place.as_local() { + if let LocalRef::Operand(op) = self.locals[index] { + if let ty::Array(_, n) = op.layout.ty.kind() { + let n = n + .try_to_target_usize(bx.tcx()) + .expect("expected monomorphic const in codegen"); + return bx.cx().const_usize(n); + } + } + } + // use common size calculation for non zero-sized types + let cg_value = self.codegen_place(bx, place.as_ref()); + cg_value.len(bx.cx()) + } + /// Codegen an `Rvalue::RawPtr` or `Rvalue::Ref` fn codegen_place_to_pointer( &mut self, @@ -1077,6 +1114,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::Ref(..) | mir::Rvalue::CopyForDeref(..) | mir::Rvalue::RawPtr(..) | + mir::Rvalue::Len(..) | mir::Rvalue::Cast(..) | // (*) mir::Rvalue::ShallowInitBox(..) | // (*) mir::Rvalue::BinaryOp(..) | diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 3ee13b19f66..bbf87a59942 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -217,6 +217,27 @@ pub trait BuilderMethods<'a, 'tcx>: dest: PlaceRef<'tcx, Self::Value>, ); + /// Emits an `assume` that the integer value `imm` of type `ty` is contained in `range`. + /// + /// This *always* emits the assumption, so you probably want to check the + /// optimization level and `Scalar::is_always_valid` before calling it. + fn assume_integer_range(&mut self, imm: Self::Value, ty: Self::Type, range: WrappingRange) { + let WrappingRange { start, end } = range; + + // Perhaps one day we'll be able to use assume operand bundles for this, + // but for now this encoding with a single icmp+assume is best per + // <https://github.com/llvm/llvm-project/issues/123278#issuecomment-2597440158> + let shifted = if start == 0 { + imm + } else { + let low = self.const_uint_big(ty, start); + self.sub(imm, low) + }; + let width = self.const_uint_big(ty, u128::wrapping_sub(end, start)); + let cmp = self.icmp(IntPredicate::IntULE, shifted, width); + self.assume(cmp); + } + fn range_metadata(&mut self, load: Self::Value, range: WrappingRange); fn nonnull_metadata(&mut self, load: Self::Value); diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 9af463a691a..d0de7ff0b5f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -9,6 +9,7 @@ pub trait ConstCodegenMethods<'tcx>: BackendTypes { /// Generate an uninitialized value (matching uninitialized memory in MIR). /// Whether memory is initialized or not is tracked byte-for-byte. fn const_undef(&self, t: Self::Type) -> Self::Value; + fn is_undef(&self, v: Self::Value) -> bool; /// Generate a fake value. Poison always affects the entire value, even if just a single byte is /// poison. This can only be used in codepaths that are already UB, i.e., UB-free Rust code /// (including code that e.g. copies uninit memory with `MaybeUninit`) can never encounter a diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 4861b7a4430..d4bfb781320 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -424,7 +424,7 @@ const_eval_unstable_in_stable_exposed = .bypass_sugg = otherwise, as a last resort `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks (this requires team approval) const_eval_unstable_intrinsic = `{$name}` is not yet stable as a const intrinsic - .help = add `#![feature({$feature})]` to the crate attributes to enable +const_eval_unstable_intrinsic_suggestion = add `#![feature({$feature})]` to the crate attributes to enable const_eval_unterminated_c_string = reading a null-terminated string starting at {$pointer} with no null found before end of allocation diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 6c940124193..ed34996a7a7 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -464,6 +464,12 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> { err_span, ); } + + fn crate_inject_span(&self) -> Option<Span> { + self.tcx.hir_crate_items(()).definitions().next().and_then(|id| { + self.tcx.crate_level_attribute_injection_span(self.tcx.local_def_id_to_hir_id(id)) + }) + } } impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { @@ -495,7 +501,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Use(_) | Rvalue::CopyForDeref(..) | Rvalue::Repeat(..) - | Rvalue::Discriminant(..) => {} + | Rvalue::Discriminant(..) + | Rvalue::Len(_) => {} Rvalue::Aggregate(kind, ..) => { if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref() @@ -579,27 +586,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { ) => {} Rvalue::ShallowInitBox(_, _) => {} - Rvalue::UnaryOp(op, operand) => { + Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(self.body, self.tcx); - match op { - UnOp::Not | UnOp::Neg => { - if is_int_bool_float_or_char(ty) { - // Int, bool, float, and char operations are fine. - } else { - span_bug!( - self.span, - "non-primitive type in `Rvalue::UnaryOp{op:?}`: {ty:?}", - ); - } - } - UnOp::PtrMetadata => { - if !ty.is_ref() && !ty.is_unsafe_ptr() { - span_bug!( - self.span, - "non-pointer type in `Rvalue::UnaryOp({op:?})`: {ty:?}", - ); - } - } + if is_int_bool_float_or_char(ty) { + // Int, bool, float, and char operations are fine. + } else { + span_bug!(self.span, "non-primitive type in `Rvalue::UnaryOp`: {:?}", ty); } } @@ -823,6 +815,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { name: intrinsic.name, feature, const_stable_indirect: is_const_stable, + suggestion: self.crate_inject_span(), }); } Some(ConstStability { level: StabilityLevel::Stable { .. }, .. }) => { @@ -911,7 +904,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { // regular stability. feature == sym::rustc_private && issue == NonZero::new(27812) - && self.tcx.sess.opts.unstable_opts.force_unstable_if_unmarked + && tcx.sess.opts.unstable_opts.force_unstable_if_unmarked }; // Even if the feature is enabled, we still need check_op to double-check // this if the callee is not safe to expose on stable. @@ -921,6 +914,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { feature, feature_enabled, safe_to_expose_on_stable: callee_safe_to_expose_on_stable, + suggestion_span: self.crate_inject_span(), }); } } diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 7d103055a7c..3c83a7b92cd 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -1,8 +1,8 @@ //! Concrete error types for all operations which may be invalid in a certain const context. use hir::{ConstContext, LangItem}; -use rustc_errors::Diag; use rustc_errors::codes::*; +use rustc_errors::{Applicability, Diag}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; @@ -388,6 +388,7 @@ pub(crate) struct FnCallUnstable { /// expose on stable. pub feature_enabled: bool, pub safe_to_expose_on_stable: bool, + pub suggestion_span: Option<Span>, } impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { @@ -407,8 +408,18 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable { def_path: ccx.tcx.def_path_str(self.def_id), }); // FIXME: make this translatable + let msg = format!("add `#![feature({})]` to the crate attributes to enable", self.feature); #[allow(rustc::untranslatable_diagnostic)] - err.help(format!("add `#![feature({})]` to the crate attributes to enable", self.feature)); + if let Some(span) = self.suggestion_span { + err.span_suggestion_verbose( + span, + msg, + format!("#![feature({})]\n", self.feature), + Applicability::MachineApplicable, + ); + } else { + err.help(msg); + } err } @@ -436,6 +447,7 @@ pub(crate) struct IntrinsicUnstable { pub name: Symbol, pub feature: Symbol, pub const_stable_indirect: bool, + pub suggestion: Option<Span>, } impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { @@ -455,6 +467,8 @@ impl<'tcx> NonConstOp<'tcx> for IntrinsicUnstable { span, name: self.name, feature: self.feature, + suggestion: self.suggestion, + help: self.suggestion.is_none(), }) } } diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index b1b7fb406b1..e244b50a4b5 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -230,7 +230,9 @@ where Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) } - Rvalue::Discriminant(place) => in_place::<Q, _>(cx, in_local, place.as_ref()), + Rvalue::Discriminant(place) | Rvalue::Len(place) => { + in_place::<Q, _>(cx, in_local, place.as_ref()) + } Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()), diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index 5a6e7ab2bee..79df63a9e84 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -197,6 +197,7 @@ where | mir::Rvalue::CopyForDeref(..) | mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::Repeat(..) + | mir::Rvalue::Len(..) | mir::Rvalue::BinaryOp(..) | mir::Rvalue::NullaryOp(..) | mir::Rvalue::UnaryOp(..) diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index 3fe78171cd9..1ee9214c4b2 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -123,12 +123,19 @@ pub(crate) struct UnstableConstFn { #[derive(Diagnostic)] #[diag(const_eval_unstable_intrinsic)] -#[help] pub(crate) struct UnstableIntrinsic { #[primary_span] pub span: Span, pub name: Symbol, pub feature: Symbol, + #[suggestion( + const_eval_unstable_intrinsic_suggestion, + code = "#![feature({feature})]\n", + applicability = "machine-applicable" + )] + pub suggestion: Option<Span>, + #[help(const_eval_unstable_intrinsic_suggestion)] + pub help: bool, } #[derive(Diagnostic)] diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 32e77fe1024..b61865be667 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -9,13 +9,12 @@ use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, mir, span_bug}; use rustc_span::source_map::Spanned; -use rustc_span::{DesugaringKind, Span}; use rustc_target::callconv::FnAbi; use tracing::{info, instrument, trace}; use super::{ FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, - Projectable, interp_ok, throw_ub, + Projectable, Scalar, interp_ok, throw_ub, }; use crate::util; @@ -81,9 +80,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { use rustc_middle::mir::StatementKind::*; match &stmt.kind { - Assign(box (place, rvalue)) => { - self.eval_rvalue_into_place(rvalue, *place, stmt.source_info.span)? - } + Assign(box (place, rvalue)) => self.eval_rvalue_into_place(rvalue, *place)?, SetDiscriminant { place, variant_index } => { let dest = self.eval_place(**place)?; @@ -162,7 +159,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &mut self, rvalue: &mir::Rvalue<'tcx>, place: mir::Place<'tcx>, - span: Span, ) -> InterpResult<'tcx> { let dest = self.eval_place(place)?; // FIXME: ensure some kind of non-aliasing between LHS and RHS? @@ -218,6 +214,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_repeat(operand, &dest)?; } + Len(place) => { + let src = self.eval_place(place)?; + let len = src.len(self)?; + self.write_scalar(Scalar::from_target_usize(len, self), &dest)?; + } + Ref(_, borrow_kind, place) => { let src = self.eval_place(place)?; let place = self.force_allocation(&src)?; @@ -248,13 +250,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let src = self.eval_place(place)?; let place = self.force_allocation(&src)?; let mut val = ImmTy::from_immediate(place.to_ref(self), dest.layout); - if !place_base_raw - && span.desugaring_kind() != Some(DesugaringKind::IndexBoundsCheckReborrow) - { + if !place_base_raw { // If this was not already raw, it needs retagging. - // As a special hack, we exclude the desugared `PtrMetadata(&raw const *_n)` - // from indexing. (Really we should not do any retag on `&raw` but that does not - // currently work with Stacked Borrows.) val = M::retag_ptr_value(self, mir::RetagKind::Raw, &val)?; } self.write_immediate(*val, &dest)?; diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index c8ecddb046c..889a8299c18 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -32,7 +32,7 @@ tracing = "0.1" version = "0.12" [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_Storage_FileSystem", diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs index 9739e501272..e761faee67b 100644 --- a/compiler/rustc_data_structures/src/flock/windows.rs +++ b/compiler/rustc_data_structures/src/flock/windows.rs @@ -60,9 +60,9 @@ impl Lock { unsafe { LockFileEx( - HANDLE(file.as_raw_handle() as isize), + HANDLE(file.as_raw_handle()), flags, - 0, + None, u32::MAX, u32::MAX, &mut overlapped, diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 2f0fe64b096..07b88e59723 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -59,7 +59,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = [ "Win32_System_Diagnostics_Debug", ] diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 0413e5e8634..20be2144609 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -28,8 +28,8 @@ use std::io::{self, IsTerminal, Read, Write}; use std::panic::{self, PanicHookInfo, catch_unwind}; use std::path::{Path, PathBuf}; use std::process::{self, Command, Stdio}; +use std::sync::OnceLock; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, OnceLock}; use std::time::{Instant, SystemTime}; use std::{env, str}; @@ -53,14 +53,13 @@ use rustc_middle::ty::TyCtxt; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_session::config::{ CG_OPTIONS, ErrorOutputType, Input, OptionDesc, OutFileName, OutputType, UnstableOptions, - Z_OPTIONS, nightly_options, + Z_OPTIONS, nightly_options, parse_target_triple, }; use rustc_session::getopts::{self, Matches}; use rustc_session::lint::{Lint, LintId}; use rustc_session::output::collect_crate_types; use rustc_session::{EarlyDiagCtxt, Session, config, filesearch}; use rustc_span::FileName; -use rustc_span::source_map::FileLoader; use rustc_target::json::ToJson; use rustc_target::spec::{Target, TargetTuple}; use time::OffsetDateTime; @@ -208,84 +207,7 @@ pub fn diagnostics_registry() -> Registry { } /// This is the primary entry point for rustc. -pub struct RunCompiler<'a> { - at_args: &'a [String], - callbacks: &'a mut (dyn Callbacks + Send), - file_loader: Option<Box<dyn FileLoader + Send + Sync>>, - make_codegen_backend: - Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>, - using_internal_features: Arc<std::sync::atomic::AtomicBool>, -} - -impl<'a> RunCompiler<'a> { - pub fn new(at_args: &'a [String], callbacks: &'a mut (dyn Callbacks + Send)) -> Self { - Self { - at_args, - callbacks, - file_loader: None, - make_codegen_backend: None, - using_internal_features: Arc::default(), - } - } - - /// Set a custom codegen backend. - /// - /// Has no uses within this repository, but is used by bjorn3 for "the - /// hotswapping branch of cg_clif" for "setting the codegen backend from a - /// custom driver where the custom codegen backend has arbitrary data." - /// (See #102759.) - pub fn set_make_codegen_backend( - &mut self, - make_codegen_backend: Option< - Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>, - >, - ) -> &mut Self { - self.make_codegen_backend = make_codegen_backend; - self - } - - /// Load files from sources other than the file system. - /// - /// Has no uses within this repository, but may be used in the future by - /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for - /// running rustc without having to save". (See #102759.) - pub fn set_file_loader( - &mut self, - file_loader: Option<Box<dyn FileLoader + Send + Sync>>, - ) -> &mut Self { - self.file_loader = file_loader; - self - } - - /// Set the session-global flag that checks whether internal features have been used, - /// suppressing the message about submitting an issue in ICEs when enabled. - #[must_use] - pub fn set_using_internal_features(mut self, using_internal_features: Arc<AtomicBool>) -> Self { - self.using_internal_features = using_internal_features; - self - } - - /// Parse args and run the compiler. - pub fn run(self) { - run_compiler( - self.at_args, - self.callbacks, - self.file_loader, - self.make_codegen_backend, - self.using_internal_features, - ); - } -} - -fn run_compiler( - at_args: &[String], - callbacks: &mut (dyn Callbacks + Send), - file_loader: Option<Box<dyn FileLoader + Send + Sync>>, - make_codegen_backend: Option< - Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>, - >, - using_internal_features: Arc<std::sync::atomic::AtomicBool>, -) { +pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) { let mut default_early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); // Throw away the first argument, the name of the binary. @@ -322,16 +244,16 @@ fn run_compiler( output_file: ofile, output_dir: odir, ice_file, - file_loader, + file_loader: None, locale_resources: DEFAULT_LOCALE_RESOURCES.to_vec(), lint_caps: Default::default(), psess_created: None, hash_untracked_state: None, register_lints: None, override_queries: None, - make_codegen_backend, + make_codegen_backend: None, registry: diagnostics_registry(), - using_internal_features, + using_internal_features: &USING_INTERNAL_FEATURES, expanded_args: args, }; @@ -916,13 +838,7 @@ pub fn version_at_macro_invocation( safe_println!("host: {}", config::host_tuple()); safe_println!("release: {release}"); - let debug_flags = matches.opt_strs("Z"); - let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); - let opts = config::Options::default(); - let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone()); - let target = config::build_target_config(early_dcx, &opts, &sysroot); - - get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_version(); + get_backend_from_raw_matches(early_dcx, matches).print_version(); } } @@ -1125,19 +1041,32 @@ pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) -> } if cg_flags.iter().any(|x| *x == "passes=list") { - let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); - - let opts = config::Options::default(); - let sysroot = filesearch::materialize_sysroot(opts.maybe_sysroot.clone()); - let target = config::build_target_config(early_dcx, &opts, &sysroot); - - get_codegen_backend(early_dcx, &sysroot, backend_name, &target).print_passes(); + get_backend_from_raw_matches(early_dcx, matches).print_passes(); return true; } false } +/// Get the codegen backend based on the raw [`Matches`]. +/// +/// `rustc -vV` and `rustc -Cpasses=list` need to get the codegen backend before we have parsed all +/// arguments and created a [`Session`]. This function reads `-Zcodegen-backend`, `--target` and +/// `--sysroot` without validating any other arguments and loads the codegen backend based on these +/// arguments. +fn get_backend_from_raw_matches( + early_dcx: &EarlyDiagCtxt, + matches: &Matches, +) -> Box<dyn CodegenBackend> { + let debug_flags = matches.opt_strs("Z"); + let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend=")); + let target = parse_target_triple(early_dcx, matches); + let sysroot = filesearch::materialize_sysroot(matches.opt_str("sysroot").map(PathBuf::from)); + let target = config::build_target_config(early_dcx, &target, &sysroot); + + get_codegen_backend(early_dcx, &sysroot, backend_name, &target) +} + fn describe_debug_flags() { safe_println!("\nAvailable options:\n"); print_flag_list("-Z", config::Z_OPTIONS); @@ -1191,15 +1120,6 @@ fn print_flag_list<T>(cmdline_opt: &str, flag_list: &[OptionDesc<T>]) { /// be public when using rustc as a library, see /// <https://github.com/rust-lang/rust/commit/2b4c33817a5aaecabf4c6598d41e190080ec119e> pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<getopts::Matches> { - if args.is_empty() { - // user did not write `-v` nor `-Z unstable-options`, so do not - // include that extra information. - let nightly_build = - rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build(); - usage(false, false, nightly_build); - return None; - } - // Parse with *all* options defined in the compiler, we don't worry about // option stability here we just want to parse as much as possible. let mut options = getopts::Options::new(); @@ -1245,7 +1165,7 @@ pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<geto // (unstable option being used on stable) nightly_options::check_nightly_options(early_dcx, &matches, &config::rustc_optgroups()); - if matches.opt_present("h") || matches.opt_present("help") { + if args.is_empty() || matches.opt_present("h") || matches.opt_present("help") { // Only show unstable options in --help if we accept unstable options. let unstable_enabled = nightly_options::is_unstable_enabled(&matches); let nightly_build = nightly_options::match_is_nightly_build(&matches); @@ -1352,6 +1272,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat }) } +pub static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false); + /// Installs a panic hook that will print the ICE message on unexpected panics. /// /// The hook is intended to be useable even by external tools. You can pass a custom @@ -1362,15 +1284,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat /// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to /// extra_info. /// -/// Returns a flag that can be set to disable the note for submitting a bug. This can be passed to -/// [`RunCompiler::set_using_internal_features`] to let macro expansion set it when encountering -/// internal features. -/// /// A custom rustc driver can skip calling this to set up a custom ICE hook. -pub fn install_ice_hook( - bug_report_url: &'static str, - extra_info: fn(&DiagCtxt), -) -> Arc<AtomicBool> { +pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&DiagCtxt)) { // If the user has not explicitly overridden "RUST_BACKTRACE", then produce // full backtraces. When a compiler ICE happens, we want to gather // as much information as possible to present in the issue opened @@ -1387,8 +1302,6 @@ pub fn install_ice_hook( } } - let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default()); - let using_internal_features_hook = Arc::clone(&using_internal_features); panic::update_hook(Box::new( move |default_hook: &(dyn Fn(&PanicHookInfo<'_>) + Send + Sync + 'static), info: &PanicHookInfo<'_>| { @@ -1440,11 +1353,9 @@ pub fn install_ice_hook( } // Print the ICE message - report_ice(info, bug_report_url, extra_info, &using_internal_features_hook); + report_ice(info, bug_report_url, extra_info, &USING_INTERNAL_FEATURES); }, )); - - using_internal_features } /// Prints the ICE message, including query stack, but without backtrace. @@ -1530,9 +1441,9 @@ fn report_ice( // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").is_some_and(|x| &x != "0"); - let num_frames = if backtrace { None } else { Some(2) }; + let limit_frames = if backtrace { None } else { Some(2) }; - interface::try_print_query_stack(dcx, num_frames, file); + interface::try_print_query_stack(dcx, limit_frames, file); // We don't trust this callback not to panic itself, so run it at the end after we're sure we've // printed all the relevant info. @@ -1585,13 +1496,11 @@ pub fn main() -> ! { init_rustc_env_logger(&early_dcx); signal_handler::install(); let mut callbacks = TimePassesCallbacks::default(); - let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); + install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ()); install_ctrlc_handler(); let exit_code = catch_with_exit_code(|| { - RunCompiler::new(&args::raw_args(&early_dcx)?, &mut callbacks) - .set_using_internal_features(using_internal_features) - .run(); + run_compiler(&args::raw_args(&early_dcx)?, &mut callbacks); Ok(()) }); diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md index 014d8c4f761..4b06395897a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0038.md +++ b/compiler/rustc_error_codes/src/error_codes/E0038.md @@ -264,15 +264,15 @@ trait Foo { ### Trait contains associated constants Just like static functions, associated constants aren't stored on the method -table. If the trait or any subtrait contain an associated constant, they cannot -be made into an object. +table. If the trait or any subtrait contain an associated constant, they are not +dyn compatible. ```compile_fail,E0038 trait Foo { const X: i32; } -impl Foo {} +impl dyn Foo {} ``` A simple workaround is to use a helper method instead: diff --git a/compiler/rustc_error_codes/src/error_codes/E0132.md b/compiler/rustc_error_codes/src/error_codes/E0132.md index 51258739b89..cbb14510ed7 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0132.md +++ b/compiler/rustc_error_codes/src/error_codes/E0132.md @@ -1,32 +1,3 @@ -A function with the `start` attribute was declared with type parameters. - -Erroneous code example: - -```compile_fail,E0132 -#![feature(start)] - -#[start] -fn f<T>() {} -``` - -It is not possible to declare type parameters on a function that has the `start` -attribute. Such a function must have the following type signature (for more -information, view [the unstable book][1]): +#### Note: this error code is no longer emitted by the compiler. -[1]: https://doc.rust-lang.org/unstable-book/language-features/start.html - -``` -# let _: -fn(isize, *const *const u8) -> isize; -``` - -Example: - -``` -#![feature(start)] - -#[start] -fn my_start(argc: isize, argv: *const *const u8) -> isize { - 0 -} -``` +A function with the `start` attribute was declared with type parameters. diff --git a/compiler/rustc_error_codes/src/error_codes/E0138.md b/compiler/rustc_error_codes/src/error_codes/E0138.md index 3f5eaea9f98..2e6ba546a16 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0138.md +++ b/compiler/rustc_error_codes/src/error_codes/E0138.md @@ -1,25 +1,3 @@ -More than one function was declared with the `#[start]` attribute. - -Erroneous code example: - -```compile_fail,E0138 -#![feature(start)] - -#[start] -fn foo(argc: isize, argv: *const *const u8) -> isize {} +#### Note: this error code is no longer emitted by the compiler. -#[start] -fn f(argc: isize, argv: *const *const u8) -> isize {} -// error: multiple 'start' functions -``` - -This error indicates that the compiler found multiple functions with the -`#[start]` attribute. This is an error because there must be a unique entry -point into a Rust program. Example: - -``` -#![feature(start)] - -#[start] -fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } // ok! -``` +More than one function was declared with the `#[start]` attribute. diff --git a/compiler/rustc_error_codes/src/error_codes/E0647.md b/compiler/rustc_error_codes/src/error_codes/E0647.md index 59bb47ba62a..e2f14b81aa6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0647.md +++ b/compiler/rustc_error_codes/src/error_codes/E0647.md @@ -1,13 +1,3 @@ -The `start` function was defined with a where clause. - -Erroneous code example: +#### Note: this error code is no longer emitted by the compiler. -```compile_fail,E0647 -#![feature(start)] - -#[start] -fn start(_: isize, _: *const *const u8) -> isize where (): Copy { - //^ error: `#[start]` function is not allowed to have a where clause - 0 -} -``` +The `start` function was defined with a where clause. diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs index 29f3277d399..0a30bdb48a0 100644 --- a/compiler/rustc_error_codes/src/lib.rs +++ b/compiler/rustc_error_codes/src/lib.rs @@ -24,6 +24,10 @@ // // Both columns are necessary because it's not possible in Rust to create a new identifier such as // `E0123` from an integer literal such as `0123`, unfortunately. +// +// Do *not* remove entries from this list. Instead, just add a note th the corresponding markdown +// file saying that this error is not emitted by the compiler any more (see E0001.md for an +// example), and remove all code examples that do not build any more. #[macro_export] macro_rules! error_codes { ($macro:path) => ( diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index 66b9adbead0..fbb6a1cc475 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -31,7 +31,7 @@ tracing = "0.1" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_Security", diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index f938352820d..991dfa1821a 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -3146,7 +3146,7 @@ impl FileWithAnnotatedLines { add_annotation_to_file(&mut output, Lrc::clone(&file), line, ann.as_line()); } let line_end = ann.line_end - 1; - let end_is_empty = file.get_line(line_end - 1).map_or(false, |s| !filter(&s)); + let end_is_empty = file.get_line(line_end - 1).is_some_and(|s| !filter(&s)); if middle < line_end && !end_is_empty { add_annotation_to_file(&mut output, Lrc::clone(&file), line_end, ann.as_line()); } diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 97df7f9265a..c1188665a05 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -463,7 +463,8 @@ impl DiagnosticSpan { // is an empty string, increase the length to include the newline so we don't // leave an empty line if start.col.0 == 0 - && suggestion.map_or(false, |(s, _)| s.is_empty()) + && let Some((suggestion, _)) = suggestion + && suggestion.is_empty() && let Ok(after) = je.sm.span_to_next_source(span) && after.starts_with('\n') { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index cc5eb9c335e..549729548f5 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -35,6 +35,7 @@ use std::backtrace::{Backtrace, BacktraceStatus}; use std::borrow::Cow; use std::cell::Cell; use std::error::Report; +use std::ffi::OsStr; use std::hash::Hash; use std::io::Write; use std::num::NonZero; @@ -1717,7 +1718,7 @@ impl DiagCtxtInner { let bugs: Vec<_> = std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(); - let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0"); + let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0")); let decorate = backtrace || self.ice_file.is_none(); let mut out = self .ice_file diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs index 3e3f35332e0..83255b82017 100644 --- a/compiler/rustc_expand/src/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -391,7 +391,7 @@ impl<'a> StripUnconfigured<'a> { validate_attr::deny_builtin_meta_unsafety(&self.sess.psess, &meta_item); ( - parse_cfg(&meta_item, self.sess).map_or(true, |meta_item| { + parse_cfg(&meta_item, self.sess).is_none_or(|meta_item| { attr::cfg_matches(meta_item, &self.sess, self.lint_node_id, self.features) }), Some(meta_item), diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 9f48835e15d..e60a9e83184 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -159,7 +159,7 @@ impl<'dcx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'dcx, 'match if self .best_failure .as_ref() - .map_or(true, |failure| failure.is_better_position(*approx_position)) + .is_none_or(|failure| failure.is_better_position(*approx_position)) { self.best_failure = Some(BestFailure { token: token.clone(), diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index ef209c2bce1..21688521ade 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -282,11 +282,13 @@ pub(super) fn transcribe<'a>( } MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => { marker.visit_span(&mut sp); + with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); let kind = token::NtIdent(*ident, *is_raw); TokenTree::token_alone(kind, sp) } MatchedSingle(ParseNtResult::Lifetime(ident, is_raw)) => { marker.visit_span(&mut sp); + with_metavar_spans(|mspans| mspans.insert(ident.span, sp)); let kind = token::NtLifetime(*ident, *is_raw); TokenTree::token_alone(kind, sp) } @@ -295,6 +297,8 @@ pub(super) fn transcribe<'a>( // `Delimiter::Invisible` to maintain parsing priorities. // `Interpolated` is currently used for such groups in rustc parser. marker.visit_span(&mut sp); + let use_span = nt.use_span(); + with_metavar_spans(|mspans| mspans.insert(use_span, sp)); TokenTree::token_alone(token::Interpolated(Lrc::clone(nt)), sp) } MatchedSeq(..) => { @@ -410,19 +414,15 @@ fn maybe_use_metavar_location( return orig_tt.clone(); } - let insert = |mspans: &mut FxHashMap<_, _>, s, ms| match mspans.try_insert(s, ms) { - Ok(_) => true, - Err(err) => *err.entry.get() == ms, // Tried to insert the same span, still success - }; marker.visit_span(&mut metavar_span); let no_collision = match orig_tt { TokenTree::Token(token, ..) => { - with_metavar_spans(|mspans| insert(mspans, token.span, metavar_span)) + with_metavar_spans(|mspans| mspans.insert(token.span, metavar_span)) } TokenTree::Delimited(dspan, ..) => with_metavar_spans(|mspans| { - insert(mspans, dspan.open, metavar_span) - && insert(mspans, dspan.close, metavar_span) - && insert(mspans, dspan.entire(), metavar_span) + mspans.insert(dspan.open, metavar_span) + && mspans.insert(dspan.close, metavar_span) + && mspans.insert(dspan.entire(), metavar_span) }), }; if no_collision || psess.source_map().is_imported(metavar_span) { @@ -434,14 +434,14 @@ fn maybe_use_metavar_location( match orig_tt { TokenTree::Token(Token { kind, span }, spacing) => { let span = metavar_span.with_ctxt(span.ctxt()); - with_metavar_spans(|mspans| insert(mspans, span, metavar_span)); + with_metavar_spans(|mspans| mspans.insert(span, metavar_span)); TokenTree::Token(Token { kind: kind.clone(), span }, *spacing) } TokenTree::Delimited(dspan, dspacing, delimiter, tts) => { let open = metavar_span.with_ctxt(dspan.open.ctxt()); let close = metavar_span.with_ctxt(dspan.close.ctxt()); with_metavar_spans(|mspans| { - insert(mspans, open, metavar_span) && insert(mspans, close, metavar_span) + mspans.insert(open, metavar_span) && mspans.insert(close, metavar_span) }); let dspan = DelimSpan::from_pair(open, close); TokenTree::Delimited(dspan, *dspacing, *delimiter, tts.clone()) diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 5510e7e09e5..68e0191f45e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -448,7 +448,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), // Entry point: - ungated!(start, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(no_start, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No), ungated!(no_main, CrateLevel, template!(Word), WarnFollowing, EncodeCrossCrate::No), diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 9aa59375706..081638715df 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -163,7 +163,7 @@ declare_features! ( /// then removed. But there was no utility storing it separately, so now /// it's in this list. (removed, no_stack_check, "1.0.0", None, None), - /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible (object safe). + /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible (object safe). /// Renamed to `dyn_compatible_for_dispatch`. (removed, object_safe_for_dispatch, "1.83.0", Some(43561), Some("renamed to `dyn_compatible_for_dispatch`")), @@ -220,8 +220,9 @@ declare_features! ( (removed, rustc_diagnostic_macros, "1.38.0", None, None), /// Allows identifying crates that contain sanitizer runtimes. (removed, sanitizer_runtime, "1.17.0", None, None), - (removed, simd, "1.0.0", Some(27731), - Some("removed in favor of `#[repr(simd)]`")), + (removed, simd, "1.0.0", Some(27731), Some("removed in favor of `#[repr(simd)]`")), + /// Allows using `#[start]` on a function indicating that it is the program entrypoint. + (removed, start, "1.0.0", Some(29633), Some("not portable enough and never RFC'd")), /// Allows `#[link(kind = "static-nobundle", ...)]`. (removed, static_nobundle, "1.16.0", Some(37403), Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#)), diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1dcde453331..1a216ebf117 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -272,7 +272,7 @@ declare_features! ( (unstable, doc_notable_trait, "1.52.0", Some(45040)), /// Allows using the `may_dangle` attribute (RFC 1327). (unstable, dropck_eyepatch, "1.10.0", Some(34761)), - /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn-compatible[^1]. + /// Allows making `dyn Trait` well-formed even if `Trait` is not dyn compatible[^1]. /// In that case, `dyn Trait: Trait` does not hold. Moreover, coercions and /// casts in safe Rust to `dyn Trait` for such a `Trait` is also forbidden. /// @@ -300,8 +300,6 @@ declare_features! ( (internal, rustdoc_internals, "1.58.0", Some(90418)), /// Allows using the `rustdoc::missing_doc_code_examples` lint (unstable, rustdoc_missing_doc_code_examples, "1.31.0", Some(101730)), - /// Allows using `#[start]` on a function indicating that it is the program entrypoint. - (unstable, start, "1.0.0", Some(29633)), /// Allows using `#[structural_match]` which indicates that a type is structurally matchable. /// FIXME: Subsumed by trait `StructuralPartialEq`, cannot move to removed until a library /// feature with the same name exists. @@ -722,7 +720,8 @@ impl Features { /// Some features are not allowed to be used together at the same time, if /// the two are present, produce an error. -/// -/// Currently empty, but we will probably need this again in the future, -/// so let's keep it in for now. -pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[]; +pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = &[ + // Experimental match ergonomics rulesets are incompatible with each other, to simplify the + // boolean logic required to tell which typing rules to use. + (sym::ref_pat_eat_one_layer_2024, sym::ref_pat_eat_one_layer_2024_structural), +]; diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index 705de389e07..7e3a8561da0 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -794,7 +794,7 @@ impl<Id> Res<Id> { /// Always returns `true` if `self` is `Res::Err` pub fn matches_ns(&self, ns: Namespace) -> bool { - self.ns().map_or(true, |actual_ns| actual_ns == ns) + self.ns().is_none_or(|actual_ns| actual_ns == ns) } /// Returns whether such a resolved path can occur in a tuple struct/variant pattern diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index fae3b778d7b..02bc069fc5f 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -332,6 +332,10 @@ language_item_table! { FallbackSurfaceDrop, sym::fallback_surface_drop, fallback_surface_drop_fn, Target::Fn, GenericRequirement::None; AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None; + /// For all binary crates without `#![no_main]`, Rust will generate a "main" function. + /// The exact name and signature are target-dependent. The "main" function will invoke + /// this lang item, passing it the `argc` and `argv` (or null, if those don't exist + /// on the current target) as well as the user-defined `fn main` from the binary crate. Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1); EhPersonality, sym::eh_personality, eh_personality, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index d7ab6eca84b..512d379687b 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -489,21 +489,6 @@ hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is hi hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable .help = add `#![feature(min_specialization)]` to the crate attributes to enable -hir_analysis_start_function_parameters = `#[start]` function is not allowed to have type parameters - .label = `#[start]` function cannot have type parameters - -hir_analysis_start_function_where = `#[start]` function is not allowed to have a `where` clause - .label = `#[start]` function cannot have a `where` clause - -hir_analysis_start_not_async = `#[start]` function is not allowed to be `async` - .label = `#[start]` is not allowed to be `async` - -hir_analysis_start_not_target_feature = `#[start]` function is not allowed to have `#[target_feature]` - .label = `#[start]` function is not allowed to have `#[target_feature]` - -hir_analysis_start_not_track_caller = `#[start]` function is not allowed to be `#[track_caller]` - .label = `#[start]` function is not allowed to be `#[track_caller]` - hir_analysis_static_specialize = cannot specialize on `'static` lifetime hir_analysis_tait_forward_compat = item constrains opaque type that is not in its signature diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index d8e9227a87c..b3eade8c8ae 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -86,7 +86,7 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { if self.infcx.next_trait_solver() && let ty::Alias(..) = ty.kind() { - let (normalized_ty, obligations) = self.structurally_normalize(ty)?; + let (normalized_ty, obligations) = self.structurally_normalize_ty(ty)?; self.state.obligations.extend(obligations); (AutoderefKind::Builtin, normalized_ty) } else { @@ -166,7 +166,7 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { } let (normalized_ty, obligations) = - self.structurally_normalize(Ty::new_projection(tcx, trait_target_def_id, [ty]))?; + self.structurally_normalize_ty(Ty::new_projection(tcx, trait_target_def_id, [ty]))?; debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); self.state.obligations.extend(obligations); @@ -174,12 +174,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { } #[instrument(level = "debug", skip(self), ret)] - pub fn structurally_normalize( + pub fn structurally_normalize_ty( &self, ty: Ty<'tcx>, ) -> Option<(Ty<'tcx>, PredicateObligations<'tcx>)> { let ocx = ObligationCtxt::new(self.infcx); - let Ok(normalized_ty) = ocx.structurally_normalize( + let Ok(normalized_ty) = ocx.structurally_normalize_ty( &traits::ObligationCause::misc(self.span, self.body_id), self.param_env, ty, diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 332ac2fa0c0..25c2f8554b7 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::span_bug; -use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode}; +use rustc_middle::ty::{self, TyCtxt, TypingMode}; use rustc_session::config::EntryFnType; use rustc_span::def_id::{CRATE_DEF_ID, DefId, LocalDefId}; use rustc_span::{Span, sym}; @@ -18,7 +18,6 @@ use crate::errors; pub(crate) fn check_for_entry_fn(tcx: TyCtxt<'_>) { match tcx.entry_fn(()) { Some((def_id, EntryFnType::Main { .. })) => check_main_fn_ty(tcx, def_id), - Some((def_id, EntryFnType::Start)) => check_start_fn_ty(tcx, def_id), _ => {} } } @@ -192,83 +191,3 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { }); } } - -fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { - let start_def_id = start_def_id.expect_local(); - let start_id = tcx.local_def_id_to_hir_id(start_def_id); - let start_span = tcx.def_span(start_def_id); - let start_t = tcx.type_of(start_def_id).instantiate_identity(); - match start_t.kind() { - ty::FnDef(..) => { - if let Node::Item(it) = tcx.hir_node(start_id) { - if let hir::ItemKind::Fn { sig, generics, .. } = &it.kind { - let mut error = false; - if !generics.params.is_empty() { - tcx.dcx().emit_err(errors::StartFunctionParameters { span: generics.span }); - error = true; - } - if generics.has_where_clause_predicates { - tcx.dcx().emit_err(errors::StartFunctionWhere { - span: generics.where_clause_span, - }); - error = true; - } - if sig.header.asyncness.is_async() { - let span = tcx.def_span(it.owner_id); - tcx.dcx().emit_err(errors::StartAsync { span }); - error = true; - } - - let attrs = tcx.hir().attrs(start_id); - for attr in attrs { - if attr.has_name(sym::track_caller) { - tcx.dcx().emit_err(errors::StartTrackCaller { - span: attr.span, - start: start_span, - }); - error = true; - } - if attr.has_name(sym::target_feature) - // Calling functions with `#[target_feature]` is - // not unsafe on WASM, see #84988 - && !tcx.sess.target.is_like_wasm - && !tcx.sess.opts.actually_rustdoc - { - tcx.dcx().emit_err(errors::StartTargetFeature { - span: attr.span, - start: start_span, - }); - error = true; - } - } - - if error { - return; - } - } - } - - let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig( - [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))], - tcx.types.isize, - false, - hir::Safety::Safe, - ExternAbi::Rust, - )); - - let _ = check_function_signature( - tcx, - ObligationCause::new( - start_span, - start_def_id, - ObligationCauseCode::StartFunctionType, - ), - start_def_id.into(), - expected_sig, - ); - } - _ => { - span_bug!(start_span, "start has a non-function type: found `{}`", start_t); - } - } -} diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index 1be4aa2f63a..4e5f0a3186a 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -13,6 +13,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_session::parse::feature_err; use rustc_span::{ErrorGuaranteed, sym}; +use rustc_type_ir::elaborate; use tracing::debug; use crate::errors; @@ -184,7 +185,7 @@ fn check_object_overlap<'tcx>( // check for overlap with the automatic `impl Trait for dyn Trait` if let ty::Dynamic(data, ..) = trait_ref.self_ty().kind() { // This is something like `impl Trait1 for Trait2`. Illegal if - // Trait1 is a supertrait of Trait2 or Trait2 is not dyn-compatible. + // Trait1 is a supertrait of Trait2 or Trait2 is not dyn compatible. let component_def_ids = data.iter().flat_map(|predicate| { match predicate.skip_binder() { @@ -205,7 +206,7 @@ fn check_object_overlap<'tcx>( // With the feature enabled, the trait is not implemented automatically, // so this is valid. } else { - let mut supertrait_def_ids = tcx.supertrait_def_ids(component_def_id); + let mut supertrait_def_ids = elaborate::supertrait_def_ids(tcx, component_def_id); if supertrait_def_ids .any(|d| d == trait_def_id && tcx.trait_def(d).implement_via_object) { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 7d651155781..d17ee86ba66 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -320,7 +320,7 @@ fn orphan_check<'tcx>( } let ty = if infcx.next_trait_solver() { - ocx.structurally_normalize( + ocx.structurally_normalize_ty( &cause, ty::ParamEnv::empty(), infcx.resolve_vars_if_possible(ty), diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 00ba1741ed7..a0f365142ba 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -620,48 +620,6 @@ pub(crate) struct TargetFeatureOnMain { } #[derive(Diagnostic)] -#[diag(hir_analysis_start_not_track_caller)] -pub(crate) struct StartTrackCaller { - #[primary_span] - pub span: Span, - #[label] - pub start: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_start_not_target_feature)] -pub(crate) struct StartTargetFeature { - #[primary_span] - pub span: Span, - #[label] - pub start: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_start_not_async, code = E0752)] -pub(crate) struct StartAsync { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_start_function_where, code = E0647)] -pub(crate) struct StartFunctionWhere { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_analysis_start_function_parameters, code = E0132)] -pub(crate) struct StartFunctionParameters { - #[primary_span] - #[label] - pub span: Span, -} - -#[derive(Diagnostic)] #[diag(hir_analysis_main_function_return_type_generic, code = E0131)] pub(crate) struct MainFunctionReturnTypeGeneric { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs index 71a5727ed6c..72ad190df7e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs @@ -4,13 +4,12 @@ use rustc_errors::struct_span_code_err; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS; -use rustc_middle::span_bug; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::{ self, DynKind, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, }; -use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span}; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{self, hir_ty_lowering_dyn_compatibility_violations}; use rustc_type_ir::elaborate::ClauseWithSupertraitSpan; @@ -30,16 +29,16 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { &self, span: Span, hir_id: hir::HirId, - hir_trait_bounds: &[hir::PolyTraitRef<'tcx>], + hir_bounds: &[hir::PolyTraitRef<'tcx>], lifetime: &hir::Lifetime, representation: DynKind, ) -> Ty<'tcx> { let tcx = self.tcx(); + let dummy_self = tcx.types.trait_object_dummy_self; - let mut bounds = Bounds::default(); + let mut user_written_bounds = Bounds::default(); let mut potential_assoc_types = Vec::new(); - let dummy_self = self.tcx().types.trait_object_dummy_self; - for trait_bound in hir_trait_bounds.iter().rev() { + for trait_bound in hir_bounds.iter() { if let hir::BoundPolarity::Maybe(_) = trait_bound.modifiers.polarity { continue; } @@ -53,92 +52,67 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { hir::BoundConstness::Never, hir::BoundPolarity::Positive, dummy_self, - &mut bounds, + &mut user_written_bounds, PredicateFilter::SelfOnly, ) { potential_assoc_types.extend(cur_potential_assoc_types); } } - let mut trait_bounds = vec![]; - let mut projection_bounds = vec![]; - for (pred, span) in bounds.clauses() { - let bound_pred = pred.kind(); - match bound_pred.skip_binder() { - ty::ClauseKind::Trait(trait_pred) => { - assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive); - trait_bounds.push((bound_pred.rebind(trait_pred.trait_ref), span)); - } - ty::ClauseKind::Projection(proj) => { - projection_bounds.push((bound_pred.rebind(proj), span)); - } - ty::ClauseKind::TypeOutlives(_) => { - // Do nothing, we deal with regions separately - } - ty::ClauseKind::RegionOutlives(_) - | ty::ClauseKind::ConstArgHasType(..) - | ty::ClauseKind::WellFormed(_) - | ty::ClauseKind::ConstEvaluatable(_) - | ty::ClauseKind::HostEffect(..) => { - span_bug!(span, "did not expect {pred} clause in object bounds"); - } - } - } - - // Expand trait aliases recursively and check that only one regular (non-auto) trait - // is used and no 'maybe' bounds are used. - let expanded_traits = - traits::expand_trait_aliases(tcx, trait_bounds.iter().map(|&(a, b)| (a, b))); - - let (mut auto_traits, regular_traits): (Vec<_>, Vec<_>) = - expanded_traits.partition(|i| tcx.trait_is_auto(i.trait_ref().def_id())); + let (trait_bounds, mut projection_bounds) = + traits::expand_trait_aliases(tcx, user_written_bounds.clauses()); + let (regular_traits, mut auto_traits): (Vec<_>, Vec<_>) = trait_bounds + .into_iter() + .partition(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); + // We don't support empty trait objects. + if regular_traits.is_empty() && auto_traits.is_empty() { + let guar = + self.report_trait_object_with_no_traits_error(span, user_written_bounds.clauses()); + return Ty::new_error(tcx, guar); + } // We don't support >1 principal if regular_traits.len() > 1 { let guar = self.report_trait_object_addition_traits_error(®ular_traits); return Ty::new_error(tcx, guar); } - // We don't support empty trait objects. - if regular_traits.is_empty() && auto_traits.is_empty() { - let guar = self.report_trait_object_with_no_traits_error(span, &trait_bounds); - return Ty::new_error(tcx, guar); - } // Don't create a dyn trait if we have errors in the principal. - if let Err(guar) = trait_bounds.error_reported() { + if let Err(guar) = regular_traits.error_reported() { return Ty::new_error(tcx, guar); } // Check that there are no gross dyn-compatibility violations; // most importantly, that the supertraits don't contain `Self`, // to avoid ICEs. - for item in ®ular_traits { - let violations = - hir_ty_lowering_dyn_compatibility_violations(tcx, item.trait_ref().def_id()); - if !violations.is_empty() { - let reported = report_dyn_incompatibility( - tcx, - span, - Some(hir_id), - item.trait_ref().def_id(), - &violations, - ) - .emit(); - return Ty::new_error(tcx, reported); + for (clause, span) in user_written_bounds.clauses() { + if let Some(trait_pred) = clause.as_trait_clause() { + let violations = + hir_ty_lowering_dyn_compatibility_violations(tcx, trait_pred.def_id()); + if !violations.is_empty() { + let reported = report_dyn_incompatibility( + tcx, + span, + Some(hir_id), + trait_pred.def_id(), + &violations, + ) + .emit(); + return Ty::new_error(tcx, reported); + } } } - let mut needed_associated_types = FxIndexSet::default(); - - let principal_span = regular_traits.first().map_or(DUMMY_SP, |info| info.bottom().1); - let regular_traits_refs_spans = trait_bounds - .into_iter() - .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id())); + let principal_trait = regular_traits.into_iter().next(); - for (base_trait_ref, original_span) in regular_traits_refs_spans { - let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx); + let mut needed_associated_types = FxIndexSet::default(); + if let Some((principal_trait, spans)) = &principal_trait { + let pred: ty::Predicate<'tcx> = (*principal_trait).upcast(tcx); for ClauseWithSupertraitSpan { pred, supertrait_span } in - traits::elaborate(tcx, [ClauseWithSupertraitSpan::new(base_pred, original_span)]) - .filter_only_self() + traits::elaborate(tcx, [ClauseWithSupertraitSpan::new( + pred, + *spans.last().unwrap(), + )]) + .filter_only_self() { debug!("observing object predicate `{pred:?}`"); @@ -179,7 +153,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // } // ``` // - // Here, the user could theoretically write `dyn MyTrait<Output = X>`, + // Here, the user could theoretically write `dyn MyTrait<MyOutput = X>`, // but actually supporting that would "expand" to an infinitely-long type // `fix $ τ → dyn MyTrait<MyOutput = X, Output = <τ as MyTrait>::MyOutput`. // @@ -188,12 +162,12 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // the discussion in #56288 for alternatives. if !references_self { // Include projections defined on supertraits. - projection_bounds.push((pred, original_span)); + projection_bounds.push((pred, supertrait_span)); } self.check_elaborated_projection_mentions_input_lifetimes( pred, - original_span, + *spans.first().unwrap(), supertrait_span, ); } @@ -202,11 +176,13 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } } - // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where <Self as Trait>::Assoc = Foo`. - // So every `Projection` clause is an `Assoc = Foo` bound. `associated_types` contains all associated - // types's `DefId`, so the following loop removes all the `DefIds` of the associated types that have a - // corresponding `Projection` clause - for (projection_bound, span) in &projection_bounds { + // `dyn Trait<Assoc = Foo>` desugars to (not Rust syntax) `dyn Trait where + // <Self as Trait>::Assoc = Foo`. So every `Projection` clause is an + // `Assoc = Foo` bound. `needed_associated_types` contains all associated + // types that we expect to be provided by the user, so the following loop + // removes all the associated types that have a corresponding `Projection` + // clause, either from expanding trait aliases or written by the user. + for &(projection_bound, span) in &projection_bounds { let def_id = projection_bound.item_def_id(); let trait_ref = tcx.anonymize_bound_vars( projection_bound.map_bound(|p| p.projection_term.trait_ref(tcx)), @@ -216,17 +192,17 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { tcx.emit_node_span_lint( UNUSED_ASSOCIATED_TYPE_BOUNDS, hir_id, - *span, - crate::errors::UnusedAssociatedTypeBounds { span: *span }, + span, + crate::errors::UnusedAssociatedTypeBounds { span }, ); } } if let Err(guar) = self.check_for_required_assoc_tys( - principal_span, + principal_trait.as_ref().map_or(smallvec![], |(_, spans)| spans.clone()), needed_associated_types, potential_assoc_types, - hir_trait_bounds, + hir_bounds, ) { return Ty::new_error(tcx, guar); } @@ -236,32 +212,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { // We remove duplicates by inserting into a `FxHashSet` to avoid re-ordering // the bounds let mut duplicates = FxHashSet::default(); - auto_traits.retain(|i| duplicates.insert(i.trait_ref().def_id())); - debug!(?regular_traits); + auto_traits.retain(|(trait_pred, _)| duplicates.insert(trait_pred.def_id())); + + debug!(?principal_trait); debug!(?auto_traits); // Erase the `dummy_self` (`trait_object_dummy_self`) used above. - let existential_trait_refs = regular_traits.iter().map(|i| { - i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { + let principal_trait_ref = principal_trait.map(|(trait_pred, spans)| { + trait_pred.map_bound(|trait_pred| { + let trait_ref = trait_pred.trait_ref; + assert_eq!(trait_pred.polarity, ty::PredicatePolarity::Positive); assert_eq!(trait_ref.self_ty(), dummy_self); + let span = *spans.first().unwrap(); + // Verify that `dummy_self` did not leak inside default type parameters. This // could not be done at path creation, since we need to see through trait aliases. let mut missing_type_params = vec![]; - let mut references_self = false; let generics = tcx.generics_of(trait_ref.def_id); let args: Vec<_> = trait_ref .args .iter() .enumerate() - .skip(1) // Remove `Self` for `ExistentialPredicate`. + // Skip `Self` + .skip(1) .map(|(index, arg)| { if arg == dummy_self.into() { let param = &generics.own_params[index]; missing_type_params.push(param.name); Ty::new_misc_error(tcx).into() } else if arg.walk().any(|arg| arg == dummy_self.into()) { - references_self = true; let guar = self.dcx().span_delayed_bug( span, "trait object trait bounds reference `Self`", @@ -273,8 +253,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { }) .collect(); - let span = i.bottom().1; - let empty_generic_args = hir_trait_bounds.iter().any(|hir_bound| { + let empty_generic_args = hir_bounds.iter().any(|hir_bound| { hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) && hir_bound.span.contains(span) }); @@ -285,26 +264,11 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { empty_generic_args, ); - if references_self { - let def_id = i.bottom().0.def_id(); - struct_span_code_err!( - self.dcx(), - i.bottom().1, - E0038, - "the {} `{}` cannot be made into an object", - tcx.def_descr(def_id), - tcx.item_name(def_id), - ) - .with_note( - rustc_middle::traits::DynCompatibilityViolation::SupertraitSelf( - smallvec![], - ) - .error_msg(), - ) - .emit(); - } - - ty::ExistentialTraitRef::new(tcx, trait_ref.def_id, args) + ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::new( + tcx, + trait_ref.def_id, + args, + )) }) }); @@ -327,21 +291,24 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar); } - ty::ExistentialProjection::erase_self_ty(tcx, b) + ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty( + tcx, b, + )) }) }); - let regular_trait_predicates = existential_trait_refs - .map(|trait_ref| trait_ref.map_bound(ty::ExistentialPredicate::Trait)); - let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { - ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) + let auto_trait_predicates = auto_traits.into_iter().map(|(trait_pred, _)| { + assert_eq!(trait_pred.polarity(), ty::PredicatePolarity::Positive); + assert_eq!(trait_pred.self_ty().skip_binder(), dummy_self); + + ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_pred.def_id())) }); + // N.b. principal, projections, auto traits // FIXME: This is actually wrong with multiple principals in regards to symbol mangling - let mut v = regular_trait_predicates - .chain( - existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)), - ) + let mut v = principal_trait_ref + .into_iter() + .chain(existential_projections) .chain(auto_trait_predicates) .collect::<SmallVec<[_; 8]>>(); v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); 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 7a3d921f00e..5d751a25080 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -11,7 +11,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::bug; use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _}; use rustc_middle::ty::{ - self, AdtDef, Binder, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeVisitableExt, + self, AdtDef, GenericParamDefKind, Ty, TyCtxt, TypeVisitableExt, suggest_constraining_type_param, }; use rustc_session::parse::feature_err; @@ -19,8 +19,9 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, kw, sym}; use rustc_trait_selection::error_reporting::traits::report_dyn_incompatibility; use rustc_trait_selection::traits::{ - FulfillmentError, TraitAliasExpansionInfo, dyn_compatibility_violations_for_assoc_item, + FulfillmentError, dyn_compatibility_violations_for_assoc_item, }; +use smallvec::SmallVec; use crate::errors::{ self, AssocItemConstraintsNotAllowedHere, ManualImplementation, MissingTypeParams, @@ -720,7 +721,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { /// emit a generic note suggesting using a `where` clause to constraint instead. pub(crate) fn check_for_required_assoc_tys( &self, - principal_span: Span, + spans: SmallVec<[Span; 1]>, missing_assoc_types: FxIndexSet<(DefId, ty::PolyTraitRef<'tcx>)>, potential_assoc_types: Vec<usize>, trait_bounds: &[hir::PolyTraitRef<'_>], @@ -729,6 +730,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { return Ok(()); } + let principal_span = *spans.first().unwrap(); + let tcx = self.tcx(); // FIXME: This logic needs some more care w.r.t handling of conflicts let missing_assoc_types: Vec<_> = missing_assoc_types @@ -1124,29 +1127,36 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn report_trait_object_addition_traits_error( &self, - regular_traits: &Vec<TraitAliasExpansionInfo<'_>>, + regular_traits: &Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>, ) -> ErrorGuaranteed { - let first_trait = ®ular_traits[0]; - let additional_trait = ®ular_traits[1]; + // we use the last span to point at the traits themselves, + // and all other preceding spans are trait alias expansions. + let (&first_span, first_alias_spans) = regular_traits[0].1.split_last().unwrap(); + let (&second_span, second_alias_spans) = regular_traits[1].1.split_last().unwrap(); let mut err = struct_span_code_err!( self.dcx(), - additional_trait.bottom().1, + *regular_traits[1].1.first().unwrap(), E0225, "only auto traits can be used as additional traits in a trait object" ); - additional_trait.label_with_exp_info( - &mut err, - "additional non-auto trait", - "additional use", - ); - first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use"); + err.span_label(first_span, "first non-auto trait"); + for &alias_span in first_alias_spans { + err.span_label(alias_span, "first non-auto trait comes from this alias"); + } + err.span_label(second_span, "additional non-auto trait"); + for &alias_span in second_alias_spans { + err.span_label(alias_span, "second non-auto trait comes from this alias"); + } err.help(format!( "consider creating a new trait with all of these as supertraits and using that \ trait here instead: `trait NewTrait: {} {{}}`", regular_traits .iter() // FIXME: This should `print_sugared`, but also needs to integrate projection bounds... - .map(|t| t.trait_ref().print_only_trait_path().to_string()) + .map(|(pred, _)| pred + .map_bound(|pred| pred.trait_ref) + .print_only_trait_path() + .to_string()) .collect::<Vec<_>>() .join(" + "), )); @@ -1161,14 +1171,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { pub fn report_trait_object_with_no_traits_error( &self, span: Span, - trait_bounds: &Vec<(Binder<'tcx, TraitRef<'tcx>>, Span)>, + user_written_clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, ) -> ErrorGuaranteed { let tcx = self.tcx(); - let trait_alias_span = trait_bounds - .iter() - .map(|&(trait_ref, _)| trait_ref.def_id()) - .find(|&trait_ref| tcx.is_trait_alias(trait_ref)) - .map(|trait_ref| tcx.def_span(trait_ref)); + let trait_alias_span = user_written_clauses + .into_iter() + .filter_map(|(clause, _)| clause.as_trait_clause()) + .find(|trait_ref| tcx.is_trait_alias(trait_ref.def_id())) + .map(|trait_ref| tcx.def_span(trait_ref.def_id())); self.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span }) } diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs index 7b07e0ee939..5d00ecbe918 100644 --- a/compiler/rustc_hir_typeck/src/cast.rs +++ b/compiler/rustc_hir_typeck/src/cast.rs @@ -45,6 +45,7 @@ use rustc_session::lint; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::{DUMMY_SP, Span, sym}; use rustc_trait_selection::infer::InferCtxtExt; +use rustc_type_ir::elaborate; use tracing::{debug, instrument}; use super::FnCtxt; @@ -923,7 +924,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { let src_auto: FxHashSet<_> = src_tty .auto_traits() .chain( - tcx.supertrait_def_ids(src_principal.def_id()) + elaborate::supertrait_def_ids(tcx, src_principal.def_id()) .filter(|def_id| tcx.trait_is_auto(*def_id)), ) .collect(); diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 6945dbc3216..47abba1cc29 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -461,9 +461,17 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // to the target type), since that should be the least // confusing. let Some(InferOk { value: ty, mut obligations }) = found else { - let err = first_error.expect("coerce_borrowed_pointer had no error"); - debug!("coerce_borrowed_pointer: failed with err = {:?}", err); - return Err(err); + if let Some(first_error) = first_error { + debug!("coerce_borrowed_pointer: failed with err = {:?}", first_error); + return Err(first_error); + } else { + // This may happen in the new trait solver since autoderef requires + // the pointee to be structurally normalizable, or else it'll just bail. + // So when we have a type like `&<not well formed>`, then we get no + // autoderef steps (even though there should be at least one). That means + // we get no type mismatches, since the loop above just exits early. + return Err(TypeError::Mismatch); + } }; if ty == a && mt_a.mutbl.is_not() && autoderef.step_count() == 1 { @@ -1124,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if self.next_trait_solver() && let ty::Alias(..) = ty.kind() { - ocx.structurally_normalize(&cause, self.param_env, ty) + ocx.structurally_normalize_ty(&cause, self.param_env, ty) } else { Ok(ty) } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 4eed2bc1238..052adaa69b2 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -19,8 +19,15 @@ use crate::fluent_generated as fluent; pub(crate) struct BaseExpressionDoubleDot { #[primary_span] pub span: Span, + #[suggestion( + hir_typeck_base_expression_double_dot_enable_default_field_values, + code = "#![feature(default_field_values)]\n", + applicability = "machine-applicable", + style = "verbose" + )] + pub default_field_values_suggestion: Option<Span>, #[subdiagnostic] - pub default_field_values: Option<BaseExpressionDoubleDotEnableDefaultFieldValues>, + pub default_field_values_help: Option<BaseExpressionDoubleDotEnableDefaultFieldValues>, #[subdiagnostic] pub add_expr: Option<BaseExpressionDoubleDotAddExpr>, #[subdiagnostic] diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 3bb518e7f97..bdd436302f4 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -1991,18 +1991,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { adt_ty: Ty<'tcx>, expected: Expectation<'tcx>, expr: &hir::Expr<'_>, - span: Span, + path_span: Span, variant: &'tcx ty::VariantDef, hir_fields: &'tcx [hir::ExprField<'tcx>], base_expr: &'tcx hir::StructTailExpr<'tcx>, ) { let tcx = self.tcx; - let adt_ty = self.try_structurally_resolve_type(span, adt_ty); + let adt_ty = self.try_structurally_resolve_type(path_span, adt_ty); let adt_ty_hint = expected.only_has_type(self).and_then(|expected| { self.fudge_inference_if_ok(|| { let ocx = ObligationCtxt::new(self); - ocx.sup(&self.misc(span), self.param_env, expected, adt_ty)?; + ocx.sup(&self.misc(path_span), self.param_env, expected, adt_ty)?; if !ocx.select_where_possible().is_empty() { return Err(TypeError::Mismatch); } @@ -2012,11 +2012,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); if let Some(adt_ty_hint) = adt_ty_hint { // re-link the variables that the fudging above can create. - self.demand_eqtype(span, adt_ty_hint, adt_ty); + self.demand_eqtype(path_span, adt_ty_hint, adt_ty); } let ty::Adt(adt, args) = adt_ty.kind() else { - span_bug!(span, "non-ADT passed to check_expr_struct_fields"); + span_bug!(path_span, "non-ADT passed to check_expr_struct_fields"); }; let adt_kind = adt.adt_kind(); @@ -2107,7 +2107,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if adt_kind == AdtKind::Union && hir_fields.len() != 1 { struct_span_code_err!( self.dcx(), - span, + path_span, E0784, "union expressions should have exactly one field", ) @@ -2138,13 +2138,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if !self.tcx.features().default_field_values() { + let sugg = self.tcx.crate_level_attribute_injection_span(expr.hir_id); self.dcx().emit_err(BaseExpressionDoubleDot { span: span.shrink_to_hi(), // We only mention enabling the feature if this is a nightly rustc *and* the // expression would make sense with the feature enabled. - default_field_values: if self.tcx.sess.is_nightly_build() + default_field_values_suggestion: if self.tcx.sess.is_nightly_build() + && missing_mandatory_fields.is_empty() + && !missing_optional_fields.is_empty() + && sugg.is_some() + { + sugg + } else { + None + }, + default_field_values_help: if self.tcx.sess.is_nightly_build() && missing_mandatory_fields.is_empty() && !missing_optional_fields.is_empty() + && sugg.is_none() { Some(BaseExpressionDoubleDotEnableDefaultFieldValues) } else { @@ -2167,6 +2178,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); return; } + if variant.fields.is_empty() { + let mut err = self.dcx().struct_span_err( + span, + format!( + "`{adt_ty}` has no fields, `..` needs at least one default field in the \ + struct definition", + ), + ); + err.span_label(path_span, "this type has no fields"); + err.emit(); + } if !missing_mandatory_fields.is_empty() { let s = pluralize!(missing_mandatory_fields.len()); let fields: Vec<_> = @@ -2316,11 +2338,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(); if !private_fields.is_empty() { - self.report_private_fields(adt_ty, span, expr.span, private_fields, hir_fields); + self.report_private_fields( + adt_ty, + path_span, + expr.span, + private_fields, + hir_fields, + ); } else { self.report_missing_fields( adt_ty, - span, + path_span, + expr.span, remaining_fields, variant, hir_fields, @@ -2358,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, adt_ty: Ty<'tcx>, span: Span, + full_span: Span, remaining_fields: UnordMap<Ident, (FieldIdx, &ty::FieldDef)>, variant: &'tcx ty::VariantDef, hir_fields: &'tcx [hir::ExprField<'tcx>], @@ -2397,6 +2427,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); err.span_label(span, format!("missing {remaining_fields_names}{truncated_fields_error}")); + if remaining_fields.items().all(|(_, (_, field))| field.value.is_some()) + && self.tcx.sess.is_nightly_build() + { + let msg = format!( + "all remaining fields have default values, {you_can} use those values with `..`", + you_can = if self.tcx.features().default_field_values() { + "you can" + } else { + "if you added `#![feature(default_field_values)]` to your crate you could" + }, + ); + if let Some(hir_field) = hir_fields.last() { + err.span_suggestion_verbose( + hir_field.span.shrink_to_hi(), + msg, + ", ..".to_string(), + Applicability::MachineApplicable, + ); + } else if hir_fields.is_empty() { + err.span_suggestion_verbose( + span.shrink_to_hi().with_hi(full_span.hi()), + msg, + " { .. }".to_string(), + Applicability::MachineApplicable, + ); + } + } + if let Some(hir_field) = hir_fields.last() { self.suggest_fru_from_range_and_emit(hir_field, variant, args, err); } else { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index be6d9570e35..e26c09e3601 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -1433,7 +1433,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in a reentrant borrow, causing an ICE. let result = self .at(&self.misc(sp), self.param_env) - .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()); + .structurally_normalize_ty(ty, &mut **self.fulfillment_cx.borrow_mut()); match result { Ok(normalized_ty) => normalized_ty, Err(errors) => { diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 46eed2db236..8e78fb3e219 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1210,7 +1210,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // - foo((), "current", 42u32, "next") // + foo((), 42u32) { - prev_extra_idx.map_or(true, |prev_extra_idx| { + prev_extra_idx.is_none_or(|prev_extra_idx| { prev_extra_idx + 1 == arg_idx.index() }) } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 53e055fdeef..16294970f05 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -1143,7 +1143,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.may_coerce(found, ty) } hir::FnRetTy::DefaultReturn(_) if in_closure => { - self.ret_coercion.as_ref().map_or(false, |ret| { + self.ret_coercion.as_ref().is_some_and(|ret| { let ret_ty = ret.borrow().expected_ty(); self.may_coerce(found, ret_ty) }) @@ -1784,14 +1784,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let results = self.typeck_results.borrow(); // First, look for a `Clone::clone` call if segment.ident.name == sym::clone - && results.type_dependent_def_id(expr.hir_id).map_or( - false, - |did| { + && results.type_dependent_def_id(expr.hir_id).is_some_and(|did| { let assoc_item = self.tcx.associated_item(did); assoc_item.container == ty::AssocItemContainer::Trait && assoc_item.container_id(self.tcx) == clone_trait_did - }, - ) + }) // If that clone call hasn't already dereferenced the self type (i.e. don't give this // diagnostic in cases where we have `(&&T).clone()` and we expect `T`). && !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..))) diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index cb21961f36b..9cd9ca040ce 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -87,7 +87,7 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDef } fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { - typeck_with_fallback(tcx, def_id, None) + typeck_with_inspect(tcx, def_id, None) } /// Same as `typeck` but `inspect` is invoked on evaluation of each root obligation. @@ -99,11 +99,11 @@ pub fn inspect_typeck<'tcx>( def_id: LocalDefId, inspect: ObligationInspector<'tcx>, ) -> &'tcx ty::TypeckResults<'tcx> { - typeck_with_fallback(tcx, def_id, Some(inspect)) + typeck_with_inspect(tcx, def_id, Some(inspect)) } #[instrument(level = "debug", skip(tcx, inspector), ret)] -fn typeck_with_fallback<'tcx>( +fn typeck_with_inspect<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, inspector: Option<ObligationInspector<'tcx>>, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 116765325a9..b9d1f93bfb8 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1,6 +1,5 @@ use std::cell::{Cell, RefCell}; use std::cmp::max; -use std::iter; use std::ops::Deref; use rustc_data_structures::fx::FxHashSet; @@ -1009,11 +1008,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { if self.tcx.is_trait_alias(trait_def_id) { // For trait aliases, recursively assume all explicitly named traits are relevant - for expansion in traits::expand_trait_aliases( - self.tcx, - iter::once((ty::Binder::dummy(trait_ref), self.span)), - ) { - let bound_trait_ref = expansion.trait_ref(); + for (bound_trait_pred, _) in + traits::expand_trait_aliases(self.tcx, [(trait_ref.upcast(self.tcx), self.span)]).0 + { + assert_eq!(bound_trait_pred.polarity(), ty::PredicatePolarity::Positive); + let bound_trait_ref = bound_trait_pred.map_bound(|pred| pred.trait_ref); for item in self.impl_or_trait_item(bound_trait_ref.def_id()) { if !self.has_applicable_self(&item) { self.record_static_candidate(CandidateSource::Trait( diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index b3d87ef4ad2..89843da9d7b 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -3761,18 +3761,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::TraitFn::Required([ident, ..]) => { ident.name == kw::SelfLower } - hir::TraitFn::Provided(body_id) => { - self.tcx.hir().body(*body_id).params.first().map_or( - false, - |param| { - matches!( - param.pat.kind, - hir::PatKind::Binding(_, _, ident, _) - if ident.name == kw::SelfLower - ) - }, - ) - } + hir::TraitFn::Provided(body_id) => self + .tcx + .hir() + .body(*body_id) + .params + .first() + .is_some_and(|param| { + matches!( + param.pat.kind, + hir::PatKind::Binding(_, _, ident, _) + if ident.name == kw::SelfLower + ) + }), _ => false, }; diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 36094657eaf..cbd1db2ca25 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -21,6 +21,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS; use rustc_session::parse::feature_err; use rustc_span::edit_distance::find_best_match_for_name; +use rustc_span::edition::Edition; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Spanned; use rustc_span::{BytePos, DUMMY_SP, Ident, Span, kw, sym}; @@ -169,15 +170,16 @@ enum AdjustMode { Pass, } -/// `ref mut` patterns (explicit or match-ergonomics) -/// are not allowed behind an `&` reference. +/// `ref mut` bindings (explicit or match-ergonomics) are not allowed behind an `&` reference. +/// Normally, the borrow checker enforces this, but for (currently experimental) match ergonomics, +/// we track this when typing patterns for two purposes: /// -/// This includes explicit `ref mut` behind `&` patterns -/// that match against `&mut` references, -/// where the code would have compiled -/// had the pattern been written as `&mut`. -/// However, the borrow checker will not catch -/// this last case, so we need to throw an error ourselves. +/// - For RFC 3627's Rule 3, when this would prevent us from binding with `ref mut`, we limit the +/// default binding mode to be by shared `ref` when it would otherwise be `ref mut`. +/// +/// - For RFC 3627's Rule 5, we allow `&` patterns to match against `&mut` references, treating them +/// as if they were shared references. Since the scrutinee is mutable in this case, the borrow +/// checker won't catch if we bind with `ref mut`, so we need to throw an error ourselves. #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum MutblCap { /// Mutability restricted to immutable. @@ -213,7 +215,67 @@ impl MutblCap { } } +/// Variations on RFC 3627's Rule 4: when do reference patterns match against inherited references? +/// +/// "Inherited reference" designates the `&`/`&mut` types that arise from using match ergonomics, i.e. +/// from matching a reference type with a non-reference pattern. E.g. when `Some(x)` matches on +/// `&mut Option<&T>`, `x` gets type `&mut &T` and the outer `&mut` is considered "inherited". +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum InheritedRefMatchRule { + /// Reference patterns consume only the inherited reference if possible, regardless of whether + /// the underlying type being matched against is a reference type. If there is no inherited + /// reference, a reference will be consumed from the underlying type. + EatOuter, + /// Reference patterns consume only a reference from the underlying type if possible. If the + /// underlying type is not a reference type, the inherited reference will be consumed. + EatInner, + /// When the underlying type is a reference type, reference patterns consume both layers of + /// reference, i.e. they both reset the binding mode and consume the reference type. Reference + /// patterns are not permitted when there is no underlying reference type, i.e. they can't eat + /// only an inherited reference. This is the current stable Rust behavior. + EatBoth, +} + impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + /// Experimental pattern feature: after matching against a shared reference, do we limit the + /// default binding mode in subpatterns to be `ref` when it would otherwise be `ref mut`? + /// This corresponds to Rule 3 of RFC 3627. + fn downgrade_mut_inside_shared(&self) -> bool { + // NB: RFC 3627 proposes stabilizing Rule 3 in all editions. If we adopt the same behavior + // across all editions, this may be removed. + self.tcx.features().ref_pat_eat_one_layer_2024() + || self.tcx.features().ref_pat_eat_one_layer_2024_structural() + } + + /// Experimental pattern feature: when do reference patterns match against inherited references? + /// This corresponds to variations on Rule 4 of RFC 3627. + fn ref_pat_matches_inherited_ref(&self, edition: Edition) -> InheritedRefMatchRule { + // NB: The particular rule used here is likely to differ across editions, so calls to this + // may need to become edition checks after match ergonomics stabilize. + if edition.at_least_rust_2024() { + if self.tcx.features().ref_pat_eat_one_layer_2024() { + InheritedRefMatchRule::EatOuter + } else if self.tcx.features().ref_pat_eat_one_layer_2024_structural() { + InheritedRefMatchRule::EatInner + } else { + // Currently, matching against an inherited ref on edition 2024 is an error. + // Use `EatBoth` as a fallback to be similar to stable Rust. + InheritedRefMatchRule::EatBoth + } + } else { + InheritedRefMatchRule::EatBoth + } + } + + /// Experimental pattern feature: do `&` patterns match against `&mut` references, treating them + /// as if they were shared references? This corresponds to Rule 5 of RFC 3627. + fn ref_pat_matches_mut_ref(&self) -> bool { + // NB: RFC 3627 proposes stabilizing Rule 5 in all editions. If we adopt the same behavior + // across all editions, this may be removed. + self.tcx.features().ref_pat_eat_one_layer_2024() + || self.tcx.features().ref_pat_eat_one_layer_2024_structural() + } + /// Type check the given top level pattern against the `expected` type. /// /// If a `Some(span)` is provided and `origin_expr` holds, @@ -474,13 +536,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }); } - let features = self.tcx.features(); - if features.ref_pat_eat_one_layer_2024() || features.ref_pat_eat_one_layer_2024_structural() - { + if self.downgrade_mut_inside_shared() { def_br = def_br.cap_ref_mutability(max_ref_mutbl.as_mutbl()); - if def_br == ByRef::Yes(Mutability::Not) { - max_ref_mutbl = MutblCap::Not; - } + } + if def_br == ByRef::Yes(Mutability::Not) { + max_ref_mutbl = MutblCap::Not; } if !pat_adjustments.is_empty() { @@ -731,6 +791,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Determine the binding mode... let bm = match user_bind_annot { BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => { + // Only mention the experimental `mut_ref` feature if if we're in edition 2024 and + // using other experimental matching features compatible with it. if pat.span.at_least_rust_2024() && (self.tcx.features().ref_pat_eat_one_layer_2024() || self.tcx.features().ref_pat_eat_one_layer_2024_structural()) @@ -2228,55 +2290,70 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { mut pat_info: PatInfo<'_, 'tcx>, ) -> Ty<'tcx> { let tcx = self.tcx; - let features = tcx.features(); - let ref_pat_eat_one_layer_2024 = features.ref_pat_eat_one_layer_2024(); - let ref_pat_eat_one_layer_2024_structural = - features.ref_pat_eat_one_layer_2024_structural(); - - let no_ref_mut_behind_and = - ref_pat_eat_one_layer_2024 || ref_pat_eat_one_layer_2024_structural; - let new_match_ergonomics = pat.span.at_least_rust_2024() && no_ref_mut_behind_and; let pat_prefix_span = inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)); - 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(pat_prefix_span); - } - } else { - pat_info.max_ref_mutbl = MutblCap::Mut; + let ref_pat_matches_mut_ref = self.ref_pat_matches_mut_ref(); + if ref_pat_matches_mut_ref && pat_mutbl == Mutability::Not { + // If `&` patterns can match against mutable reference types (RFC 3627, Rule 5), we need + // to prevent subpatterns from binding with `ref mut`. Subpatterns of a shared reference + // pattern should have read-only access to the scrutinee, and the borrow checker won't + // catch it in this case. + pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(pat_prefix_span); } expected = self.try_structurally_resolve_type(pat.span, expected); - if new_match_ergonomics { - if let ByRef::Yes(inh_mut) = pat_info.binding_mode { - if !ref_pat_eat_one_layer_2024 && let ty::Ref(_, _, r_mutbl) = *expected.kind() { - // Don't attempt to consume inherited reference - pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl); - } else { + // Determine whether we're consuming an inherited reference and resetting the default + // binding mode, based on edition and enabled experimental features. + if let ByRef::Yes(inh_mut) = pat_info.binding_mode { + match self.ref_pat_matches_inherited_ref(pat.span.edition()) { + InheritedRefMatchRule::EatOuter => { // ref pattern attempts to consume inherited reference if pat_mutbl > inh_mut { // Tried to match inherited `ref` with `&mut` - if !ref_pat_eat_one_layer_2024_structural { - let err_msg = "mismatched types"; - let err = if let Some(span) = pat_prefix_span { - let mut err = self.dcx().struct_span_err(span, err_msg); - err.code(E0308); - err.note("cannot match inherited `&` with `&mut` pattern"); - 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(); + // NB: This assumes that `&` patterns can match against mutable references + // (RFC 3627, Rule 5). If we implement a pattern typing ruleset with Rule 4E + // but not Rule 5, we'll need to check that here. + debug_assert!(ref_pat_matches_mut_ref); + let err_msg = "mismatched types"; + let err = if let Some(span) = pat_prefix_span { + let mut err = self.dcx().struct_span_err(span, err_msg); + err.code(E0308); + err.note("cannot match inherited `&` with `&mut` pattern"); + 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(); + } + pat_info.binding_mode = ByRef::No; + self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id); + self.check_pat(inner, expected, pat_info); + return expected; + } + InheritedRefMatchRule::EatInner => { + if let ty::Ref(_, _, r_mutbl) = *expected.kind() { + // Match against the reference type; don't consume the inherited ref. + pat_info.binding_mode = pat_info.binding_mode.cap_ref_mutability(r_mutbl); + } else { + // The expected type isn't a reference, so match against the inherited ref. + if pat_mutbl > inh_mut { + // We can't match an inherited shared reference with `&mut`. This will + // be a type error later, since we're matching a reference pattern + // against a non-reference type. + // NB: This assumes that `&` patterns can match against mutable + // references (RFC 3627, Rule 5). If we implement a pattern typing + // ruleset with Rule 4 but not Rule 5, we'll need to check that here. + debug_assert!(ref_pat_matches_mut_ref); + } else { pat_info.binding_mode = ByRef::No; self.typeck_results .borrow_mut() @@ -2285,24 +2362,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_pat(inner, expected, pat_info); return expected; } - } else { - pat_info.binding_mode = ByRef::No; - 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 - if pat_info.binding_mode != ByRef::No { - pat_info.binding_mode = ByRef::No; - self.add_rust_2024_migration_desugared_pat( - pat_info.top_info.hir_id, - pat.span, - inner.span, - "cannot implicitly match against multiple layers of reference", - ) + InheritedRefMatchRule::EatBoth => { + // Reset binding mode on old editions + pat_info.binding_mode = ByRef::No; + self.add_rust_2024_migration_desugared_pat( + pat_info.top_info.hir_id, + pat.span, + inner.span, + "cannot implicitly match against multiple layers of reference", + ) + } } } @@ -2317,10 +2388,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("check_pat_ref: expected={:?}", expected); match *expected.kind() { ty::Ref(_, r_ty, r_mutbl) - if (no_ref_mut_behind_and && r_mutbl >= pat_mutbl) + if (ref_pat_matches_mut_ref && r_mutbl >= pat_mutbl) || r_mutbl == pat_mutbl => { - if no_ref_mut_behind_and && r_mutbl == Mutability::Not { + if r_mutbl == Mutability::Not { pat_info.max_ref_mutbl = MutblCap::Not; } diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs index 34f541a8cc6..a3d87f59567 100644 --- a/compiler/rustc_index/src/interval.rs +++ b/compiler/rustc_index/src/interval.rs @@ -258,7 +258,7 @@ impl<I: Idx> IntervalSet<I> { } current = Some(*end); } - current.map_or(true, |x| x < self.domain as u32) + current.is_none_or(|x| x < self.domain as u32) } } diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index 5fc9b679c8a..69ab0e69e21 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -114,7 +114,7 @@ impl<'tcx> rustc_type_ir::InferCtxtLike for InferCtxt<'tcx> { ) } - fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>> + Copy, U>( + fn enter_forall<T: TypeFoldable<TyCtxt<'tcx>>, U>( &self, value: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U, diff --git a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs index 7908733e734..061f7e6c22a 100644 --- a/compiler/rustc_infer/src/infer/relate/higher_ranked.rs +++ b/compiler/rustc_infer/src/infer/relate/higher_ranked.rs @@ -24,9 +24,9 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self), ret)] pub fn enter_forall_and_leak_universe<T>(&self, binder: ty::Binder<'tcx, T>) -> T where - T: TypeFoldable<TyCtxt<'tcx>> + Copy, + T: TypeFoldable<TyCtxt<'tcx>>, { - if let Some(inner) = binder.no_bound_vars() { + if let Some(inner) = binder.clone().no_bound_vars() { return inner; } @@ -71,7 +71,7 @@ impl<'tcx> InferCtxt<'tcx> { #[instrument(level = "debug", skip(self, f))] pub fn enter_forall<T, U>(&self, forall: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U) -> U where - T: TypeFoldable<TyCtxt<'tcx>> + Copy, + T: TypeFoldable<TyCtxt<'tcx>>, { // FIXME: currently we do nothing to prevent placeholders with the new universe being // used after exiting `f`. For example region subtyping can result in outlives constraints diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs index ab8ada1596c..66ed49fe326 100644 --- a/compiler/rustc_infer/src/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxHashSet; -use rustc_middle::ty::{self, ToPolyTraitRef, TyCtxt}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{Ident, Span}; pub use rustc_type_ir::elaborate::*; @@ -125,8 +125,8 @@ pub fn transitive_bounds_that_define_assoc_item<'tcx>( .iter_identity_copied() .map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref)) .filter_map(|clause| clause.as_trait_clause()) - // FIXME: Negative supertraits are elaborated here lol - .map(|trait_pred| trait_pred.to_poly_trait_ref()), + .filter(|clause| clause.polarity() == ty::PredicatePolarity::Positive) + .map(|clause| clause.map_bound(|clause| clause.trait_ref)), ); return Some(trait_ref); diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 1456255ea14..2113345eda3 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -1,6 +1,5 @@ use std::path::PathBuf; use std::result; -use std::sync::Arc; use rustc_ast::{LitKind, MetaItemKind, token}; use rustc_codegen_ssa::traits::CodegenBackend; @@ -309,6 +308,11 @@ pub struct Config { pub output_dir: Option<PathBuf>, pub output_file: Option<OutFileName>, pub ice_file: Option<PathBuf>, + /// Load files from sources other than the file system. + /// + /// Has no uses within this repository, but may be used in the future by + /// bjorn3 for "hooking rust-analyzer's VFS into rustc at some point for + /// running rustc without having to save". (See #102759.) pub file_loader: Option<Box<dyn FileLoader + Send + Sync>>, /// The list of fluent resources, used for lints declared with /// [`Diagnostic`](rustc_errors::Diagnostic) and [`LintDiagnostic`](rustc_errors::LintDiagnostic). @@ -337,6 +341,11 @@ pub struct Config { pub override_queries: Option<fn(&Session, &mut Providers)>, /// This is a callback from the driver that is called to create a codegen backend. + /// + /// Has no uses within this repository, but is used by bjorn3 for "the + /// hotswapping branch of cg_clif" for "setting the codegen backend from a + /// custom driver where the custom codegen backend has arbitrary data." + /// (See #102759.) pub make_codegen_backend: Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>, @@ -346,8 +355,7 @@ pub struct Config { /// The inner atomic value is set to true when a feature marked as `internal` is /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with /// internal features are wontfix, and they are usually the cause of the ICEs. - /// None signifies that this is not tracked. - pub using_internal_features: Arc<std::sync::atomic::AtomicBool>, + pub using_internal_features: &'static std::sync::atomic::AtomicBool, /// All commandline args used to invoke the compiler, with @file args fully expanded. /// This will only be used within debug info, e.g. in the pdb file on windows @@ -383,7 +391,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se crate::callbacks::setup_callbacks(); let sysroot = filesearch::materialize_sysroot(config.opts.maybe_sysroot.clone()); - let target = config::build_target_config(&early_dcx, &config.opts, &sysroot); + let target = config::build_target_config(&early_dcx, &config.opts.target_triple, &sysroot); let file_loader = config.file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); let path_mapping = config.opts.file_path_mapping(); let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target); @@ -533,7 +541,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se pub fn try_print_query_stack( dcx: DiagCtxtHandle<'_>, - num_frames: Option<usize>, + limit_frames: Option<usize>, file: Option<std::fs::File>, ) { eprintln!("query stack during panic:"); @@ -541,13 +549,13 @@ pub fn try_print_query_stack( // Be careful relying on global state here: this code is called from // a panic hook, which means that the global `DiagCtxt` may be in a weird // state if it was responsible for triggering the panic. - let i = ty::tls::with_context_opt(|icx| { + let all_frames = ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { ty::print::with_no_queries!(print_query_stack( QueryCtxt::new(icx.tcx), icx.query, dcx, - num_frames, + limit_frames, file, )) } else { @@ -555,9 +563,14 @@ pub fn try_print_query_stack( } }); - if num_frames == None || num_frames >= Some(i) { - eprintln!("end of query stack"); + if let Some(limit_frames) = limit_frames + && all_frames > limit_frames + { + eprintln!( + "... and {} other queries... use `env RUST_BACKTRACE=1` to see the full query stack", + all_frames - limit_frames + ); } else { - eprintln!("we're just showing a limited slice of the query stack"); + eprintln!("end of query stack"); } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index aff66e48fbb..241bc35857a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -875,6 +875,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { }); // Freeze definitions as we don't add new ones at this point. // We need to wait until now since we synthesize a by-move body + // for all coroutine-closures. + // // This improves performance by allowing lock-free access to them. tcx.untracked().definitions.freeze(); @@ -887,7 +889,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { }); }); sess.time("MIR_effect_checking", || { - for def_id in tcx.hir().body_owners() { + tcx.hir().par_body_owners(|def_id| { tcx.ensure().has_ffi_unwind_calls(def_id); // If we need to codegen, ensure that we emit all errors from @@ -898,15 +900,17 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { { tcx.ensure().mir_drops_elaborated_and_const_checked(def_id); } - } + }); }); - tcx.hir().par_body_owners(|def_id| { - if tcx.is_coroutine(def_id.to_def_id()) { - tcx.ensure().mir_coroutine_witnesses(def_id); - tcx.ensure().check_coroutine_obligations( - tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), - ); - } + sess.time("coroutine_obligations", || { + tcx.hir().par_body_owners(|def_id| { + if tcx.is_coroutine(def_id.to_def_id()) { + tcx.ensure().mir_coroutine_witnesses(def_id); + tcx.ensure().check_coroutine_obligations( + tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), + ); + } + }); }); sess.time("layout_testing", || layout_test::test_layout(tcx)); diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 07c4b898721..74d02ac2227 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, BTreeSet}; use std::num::NonZero; use std::path::{Path, PathBuf}; -use std::sync::Arc; +use std::sync::atomic::AtomicBool; use rustc_data_structures::profiling::TimePassesFormat; use rustc_errors::emitter::HumanReadableErrorType; @@ -42,7 +42,8 @@ where let matches = optgroups().parse(args).unwrap(); let sessopts = build_session_options(&mut early_dcx, &matches); let sysroot = filesearch::materialize_sysroot(sessopts.maybe_sysroot.clone()); - let target = rustc_session::config::build_target_config(&early_dcx, &sessopts, &sysroot); + let target = + rustc_session::config::build_target_config(&early_dcx, &sessopts.target_triple, &sysroot); let hash_kind = sessopts.unstable_opts.src_hash_algorithm(&target); let checksum_hash_kind = sessopts.unstable_opts.checksum_hash_algorithm(); let sm_inputs = Some(SourceMapInputs { @@ -61,6 +62,8 @@ where temps_dir, }; + static USING_INTERNAL_FEATURES: AtomicBool = AtomicBool::new(false); + let sess = build_session( early_dcx, sessopts, @@ -73,7 +76,7 @@ where sysroot, "", None, - Arc::default(), + &USING_INTERNAL_FEATURES, Default::default(), ); let cfg = parse_cfg(sess.dcx(), matches.opt_strs("cfg")); diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 7522e21d0ef..64c8f00cc83 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -209,7 +209,9 @@ lint_dangling_pointers_from_temporaries = a dangling pointer will be produced be .label_ptr = this pointer will immediately be invalid .label_temporary = this `{$ty}` is deallocated at the end of the statement, bind it to a variable to extend its lifetime .note = pointers do not have a lifetime; when calling `{$callee}` the `{$ty}` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned - .help = for more information, see <https://doc.rust-lang.org/reference/destructors.html> + .help_bind = you must make sure that the variable you bind the `{$ty}` to lives at least as long as the pointer returned by the call to `{$callee}` + .help_returned = in particular, if this pointer is returned from the current function, binding the `{$ty}` inside the function will not suffice + .help_visit = for more information, see <https://doc.rust-lang.org/reference/destructors.html> lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary @@ -970,6 +972,8 @@ lint_unused_result = unused result of type `{$ty}` lint_use_let_underscore_ignore_suggestion = use `let _ = ...` to ignore the expression or result +lint_uses_power_alignment = repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + lint_variant_size_differences = enum variant is more than three times larger ({$largest} bytes) than the next largest diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 289e2c9b722..ef79f1301e5 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -57,7 +57,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) { let expect_id = canonicalize_id(expect_id); if !fulfilled_expectations.contains(&expect_id) - && tool_filter.map_or(true, |filter| expectation.lint_tool == Some(filter)) + && tool_filter.is_none_or(|filter| expectation.lint_tool == Some(filter)) { let rationale = expectation.reason.map(|rationale| ExpectationNote { rationale }); let note = expectation.is_unfulfilled_lint_expectations; diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs index 259ea908fc6..b5a6159bd0a 100644 --- a/compiler/rustc_lint/src/if_let_rescope.rs +++ b/compiler/rustc_lint/src/if_let_rescope.rs @@ -9,7 +9,7 @@ use rustc_errors::{ use rustc_hir::{self as hir, HirIdSet}; use rustc_macros::LintDiagnostic; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::{FutureIncompatibilityReason, Level}; +use rustc_session::lint::{FutureIncompatibilityReason, LintId}; use rustc_session::{declare_lint, impl_lint_pass}; use rustc_span::Span; use rustc_span::edition::Edition; @@ -245,12 +245,12 @@ impl_lint_pass!( impl<'tcx> LateLintPass<'tcx> for IfLetRescope { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { - if expr.span.edition().at_least_rust_2024() { - return; - } - if let (Level::Allow, _) = cx.tcx.lint_level_at_node(IF_LET_RESCOPE, expr.hir_id) { + if expr.span.edition().at_least_rust_2024() + || cx.tcx.lints_that_dont_need_to_run(()).contains(&LintId::of(IF_LET_RESCOPE)) + { return; } + if let hir::ExprKind::Loop(block, _label, hir::LoopSource::While, _span) = expr.kind && let Some(value) = block.expr && let hir::ExprKind::If(cond, _conseq, _alt) = value.kind @@ -290,7 +290,6 @@ struct IfLetRescopeLint { rewrite: Option<IfLetRescopeRewrite>, } -// #[derive(Subdiagnostic)] struct IfLetRescopeRewrite { match_heads: Vec<SingleArmMatchBegin>, consequent_heads: Vec<ConsequentRewrite>, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index ac995b59caf..2f610802ff5 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1139,7 +1139,9 @@ pub(crate) struct IgnoredUnlessCrateSpecified<'a> { #[derive(LintDiagnostic)] #[diag(lint_dangling_pointers_from_temporaries)] #[note] -#[help] +#[help(lint_help_bind)] +#[help(lint_help_returned)] +#[help(lint_help_visit)] // FIXME: put #[primary_span] on `ptr_span` once it does not cause conflicts pub(crate) struct DanglingPointersFromTemporaries<'tcx> { pub callee: Symbol, @@ -1693,6 +1695,10 @@ pub(crate) struct OverflowingLiteral<'a> { } #[derive(LintDiagnostic)] +#[diag(lint_uses_power_alignment)] +pub(crate) struct UsesPowerAlignment; + +#[derive(LintDiagnostic)] #[diag(lint_unused_comparisons)] pub(crate) struct UnusedComparisons; diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 3bd27a224e7..0757e6840c6 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,14 +1,15 @@ use std::iter; use std::ops::ControlFlow; -use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, Variants, WrappingRange}; +use rustc_abi::{BackendRepr, ExternAbi, TagEncoding, VariantIdx, Variants, WrappingRange}; use rustc_data_structures::fx::FxHashSet; use rustc_errors::DiagMessage; use rustc_hir::{Expr, ExprKind, LangItem}; use rustc_middle::bug; use rustc_middle::ty::layout::{LayoutOf, SizeSkeleton}; use rustc_middle::ty::{ - self, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + self, Adt, AdtKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, }; use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass}; use rustc_span::def_id::LocalDefId; @@ -23,7 +24,7 @@ use crate::lints::{ AmbiguousWidePointerComparisonsAddrSuggestion, AtomicOrderingFence, AtomicOrderingLoad, AtomicOrderingStore, ImproperCTypes, InvalidAtomicOrderingDiag, InvalidNanComparisons, InvalidNanComparisonsSuggestion, UnpredictableFunctionPointerComparisons, - UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, + UnpredictableFunctionPointerComparisonsSuggestion, UnusedComparisons, UsesPowerAlignment, VariantSizeDifferencesDiag, }; use crate::{LateContext, LateLintPass, LintContext, fluent_generated as fluent}; @@ -727,7 +728,60 @@ declare_lint! { "proper use of libc types in foreign item definitions" } -declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS]); +declare_lint! { + /// The `uses_power_alignment` lint detects specific `repr(C)` + /// aggregates on AIX. + /// In its platform C ABI, AIX uses the "power" (as in PowerPC) alignment + /// rule (detailed in https://www.ibm.com/docs/en/xl-c-and-cpp-aix/16.1?topic=data-using-alignment-modes#alignment), + /// which can also be set for XLC by `#pragma align(power)` or + /// `-qalign=power`. Aggregates with a floating-point type as the + /// recursively first field (as in "at offset 0") modify the layout of + /// *subsequent* fields of the associated structs to use an alignment value + /// where the floating-point type is aligned on a 4-byte boundary. + /// + /// The power alignment rule for structs needed for C compatibility is + /// unimplementable within `repr(C)` in the compiler without building in + /// handling of references to packed fields and infectious nested layouts, + /// so a warning is produced in these situations. + /// + /// ### Example + /// + /// ```rust,ignore (fails on non-powerpc64-ibm-aix) + /// #[repr(C)] + /// pub struct Floats { + /// a: f64, + /// b: u8, + /// c: f64, + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + /// --> <source>:5:3 + /// | + /// 5 | c: f64, + /// | ^^^^^^ + /// | + /// = note: `#[warn(uses_power_alignment)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// The power alignment rule specifies that the above struct has the + /// following alignment: + /// - offset_of!(Floats, a) == 0 + /// - offset_of!(Floats, b) == 8 + /// - offset_of!(Floats, c) == 12 + /// However, rust currently aligns `c` at offset_of!(Floats, c) == 16. + /// Thus, a warning should be produced for the above struct in this case. + USES_POWER_ALIGNMENT, + Warn, + "Structs do not follow the power alignment rule under repr(C)" +} + +declare_lint_pass!(ImproperCTypesDefinitions => [IMPROPER_CTYPES_DEFINITIONS, USES_POWER_ALIGNMENT]); #[derive(Clone, Copy)] pub(crate) enum CItemKind { @@ -1539,6 +1593,71 @@ impl ImproperCTypesDefinitions { vis.check_type_for_ffi_and_report_errors(span, fn_ptr_ty, true, false); } } + + fn check_arg_for_power_alignment<'tcx>( + &mut self, + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + ) -> bool { + // Structs (under repr(C)) follow the power alignment rule if: + // - the first field of the struct is a floating-point type that + // is greater than 4-bytes, or + // - the first field of the struct is an aggregate whose + // recursively first field is a floating-point type greater than + // 4 bytes. + if cx.tcx.sess.target.os != "aix" { + return false; + } + if ty.is_floating_point() && ty.primitive_size(cx.tcx).bytes() > 4 { + return true; + } else if let Adt(adt_def, _) = ty.kind() + && adt_def.is_struct() + { + let struct_variant = adt_def.variant(VariantIdx::ZERO); + // Within a nested struct, all fields are examined to correctly + // report if any fields after the nested struct within the + // original struct are misaligned. + for struct_field in &struct_variant.fields { + let field_ty = cx.tcx.type_of(struct_field.did).instantiate_identity(); + if self.check_arg_for_power_alignment(cx, field_ty) { + return true; + } + } + } + return false; + } + + fn check_struct_for_power_alignment<'tcx>( + &mut self, + cx: &LateContext<'tcx>, + item: &'tcx hir::Item<'tcx>, + ) { + let adt_def = cx.tcx.adt_def(item.owner_id.to_def_id()); + if adt_def.repr().c() + && !adt_def.repr().packed() + && cx.tcx.sess.target.os == "aix" + && !adt_def.all_fields().next().is_none() + { + let struct_variant_data = item.expect_struct().0; + for (index, ..) in struct_variant_data.fields().iter().enumerate() { + // Struct fields (after the first field) are checked for the + // power alignment rule, as fields after the first are likely + // to be the fields that are misaligned. + if index != 0 { + let first_field_def = struct_variant_data.fields()[index]; + let def_id = first_field_def.def_id; + let ty = cx.tcx.type_of(def_id).instantiate_identity(); + if self.check_arg_for_power_alignment(cx, ty) { + cx.emit_span_lint( + USES_POWER_ALIGNMENT, + first_field_def.span, + UsesPowerAlignment, + ); + } + } + } + } + } } /// `ImproperCTypesDefinitions` checks items outside of foreign items (e.g. stuff that isn't in @@ -1562,8 +1681,13 @@ impl<'tcx> LateLintPass<'tcx> for ImproperCTypesDefinitions { } // See `check_fn`.. hir::ItemKind::Fn { .. } => {} + // Structs are checked based on if they follow the power alignment + // rule (under repr(C)). + hir::ItemKind::Struct(..) => { + self.check_struct_for_power_alignment(cx, item); + } // See `check_field_def`.. - hir::ItemKind::Union(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Enum(..) => {} + hir::ItemKind::Union(..) | hir::ItemKind::Enum(..) => {} // Doesn't define something that can contain a external type to be checked. hir::ItemKind::Impl(..) | hir::ItemKind::TraitAlias(..) diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index dd72ea2497f..35186778671 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -2,6 +2,7 @@ #include "llvm-c/Analysis.h" #include "llvm-c/Core.h" +#include "llvm-c/DebugInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -676,120 +677,73 @@ template <typename DIT> DIT *unwrapDIPtr(LLVMMetadataRef Ref) { #define DIArray DINodeArray #define unwrapDI unwrapDIPtr -// These values **must** match debuginfo::DIFlags! They also *happen* -// to match LLVM, but that isn't required as we do giant sets of -// matching below. The value shouldn't be directly passed to LLVM. -enum class LLVMRustDIFlags : uint32_t { - FlagZero = 0, - FlagPrivate = 1, - FlagProtected = 2, - FlagPublic = 3, - FlagFwdDecl = (1 << 2), - FlagAppleBlock = (1 << 3), - FlagBlockByrefStruct = (1 << 4), - FlagVirtual = (1 << 5), - FlagArtificial = (1 << 6), - FlagExplicit = (1 << 7), - FlagPrototyped = (1 << 8), - FlagObjcClassComplete = (1 << 9), - FlagObjectPointer = (1 << 10), - FlagVector = (1 << 11), - FlagStaticMember = (1 << 12), - FlagLValueReference = (1 << 13), - FlagRValueReference = (1 << 14), - FlagExternalTypeRef = (1 << 15), - FlagIntroducedVirtual = (1 << 18), - FlagBitField = (1 << 19), - FlagNoReturn = (1 << 20), - // Do not add values that are not supported by the minimum LLVM - // version we support! see llvm/include/llvm/IR/DebugInfoFlags.def -}; - -inline LLVMRustDIFlags operator&(LLVMRustDIFlags A, LLVMRustDIFlags B) { - return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) & - static_cast<uint32_t>(B)); -} - -inline LLVMRustDIFlags operator|(LLVMRustDIFlags A, LLVMRustDIFlags B) { - return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(A) | - static_cast<uint32_t>(B)); -} - -inline LLVMRustDIFlags &operator|=(LLVMRustDIFlags &A, LLVMRustDIFlags B) { - return A = A | B; -} - -inline bool isSet(LLVMRustDIFlags F) { return F != LLVMRustDIFlags::FlagZero; } - -inline LLVMRustDIFlags visibility(LLVMRustDIFlags F) { - return static_cast<LLVMRustDIFlags>(static_cast<uint32_t>(F) & 0x3); -} - -static DINode::DIFlags fromRust(LLVMRustDIFlags Flags) { - DINode::DIFlags Result = DINode::DIFlags::FlagZero; - - switch (visibility(Flags)) { - case LLVMRustDIFlags::FlagPrivate: - Result |= DINode::DIFlags::FlagPrivate; - break; - case LLVMRustDIFlags::FlagProtected: - Result |= DINode::DIFlags::FlagProtected; - break; - case LLVMRustDIFlags::FlagPublic: - Result |= DINode::DIFlags::FlagPublic; - break; - default: - // The rest are handled below - break; - } - - if (isSet(Flags & LLVMRustDIFlags::FlagFwdDecl)) { - Result |= DINode::DIFlags::FlagFwdDecl; - } - if (isSet(Flags & LLVMRustDIFlags::FlagAppleBlock)) { - Result |= DINode::DIFlags::FlagAppleBlock; - } - if (isSet(Flags & LLVMRustDIFlags::FlagVirtual)) { - Result |= DINode::DIFlags::FlagVirtual; - } - if (isSet(Flags & LLVMRustDIFlags::FlagArtificial)) { - Result |= DINode::DIFlags::FlagArtificial; - } - if (isSet(Flags & LLVMRustDIFlags::FlagExplicit)) { - Result |= DINode::DIFlags::FlagExplicit; - } - if (isSet(Flags & LLVMRustDIFlags::FlagPrototyped)) { - Result |= DINode::DIFlags::FlagPrototyped; - } - if (isSet(Flags & LLVMRustDIFlags::FlagObjcClassComplete)) { - Result |= DINode::DIFlags::FlagObjcClassComplete; - } - if (isSet(Flags & LLVMRustDIFlags::FlagObjectPointer)) { - Result |= DINode::DIFlags::FlagObjectPointer; - } - if (isSet(Flags & LLVMRustDIFlags::FlagVector)) { - Result |= DINode::DIFlags::FlagVector; - } - if (isSet(Flags & LLVMRustDIFlags::FlagStaticMember)) { - Result |= DINode::DIFlags::FlagStaticMember; - } - if (isSet(Flags & LLVMRustDIFlags::FlagLValueReference)) { - Result |= DINode::DIFlags::FlagLValueReference; - } - if (isSet(Flags & LLVMRustDIFlags::FlagRValueReference)) { - Result |= DINode::DIFlags::FlagRValueReference; - } - if (isSet(Flags & LLVMRustDIFlags::FlagIntroducedVirtual)) { - Result |= DINode::DIFlags::FlagIntroducedVirtual; - } - if (isSet(Flags & LLVMRustDIFlags::FlagBitField)) { - Result |= DINode::DIFlags::FlagBitField; - } - if (isSet(Flags & LLVMRustDIFlags::FlagNoReturn)) { - Result |= DINode::DIFlags::FlagNoReturn; - } - - return Result; +// FIXME(Zalathar): This is a temporary typedef to avoid churning dozens of +// bindings that are going to be deleted and replaced with their LLVM-C +// equivalents, as part of #134009. After that happens, the remaining bindings +// can be adjusted to use `LLVMDIFlags` instead of relying on this typedef. +typedef LLVMDIFlags LLVMRustDIFlags; + +// Statically assert that `LLVMDIFlags` (C) and `DIFlags` (C++) have the same +// layout, at least for the flags we know about. This isn't guaranteed, but is +// likely to remain true, and as long as it is true it makes conversions easy. +#define ASSERT_DIFLAG_VALUE(FLAG, VALUE) \ + static_assert((LLVMDI##FLAG == (VALUE)) && (DINode::DIFlags::FLAG == (VALUE))) +ASSERT_DIFLAG_VALUE(FlagZero, 0); +ASSERT_DIFLAG_VALUE(FlagPrivate, 1); +ASSERT_DIFLAG_VALUE(FlagProtected, 2); +ASSERT_DIFLAG_VALUE(FlagPublic, 3); +// Bit (1 << 1) is part of the private/protected/public values above. +ASSERT_DIFLAG_VALUE(FlagFwdDecl, 1 << 2); +ASSERT_DIFLAG_VALUE(FlagAppleBlock, 1 << 3); +ASSERT_DIFLAG_VALUE(FlagReservedBit4, 1 << 4); +ASSERT_DIFLAG_VALUE(FlagVirtual, 1 << 5); +ASSERT_DIFLAG_VALUE(FlagArtificial, 1 << 6); +ASSERT_DIFLAG_VALUE(FlagExplicit, 1 << 7); +ASSERT_DIFLAG_VALUE(FlagPrototyped, 1 << 8); +ASSERT_DIFLAG_VALUE(FlagObjcClassComplete, 1 << 9); +ASSERT_DIFLAG_VALUE(FlagObjectPointer, 1 << 10); +ASSERT_DIFLAG_VALUE(FlagVector, 1 << 11); +ASSERT_DIFLAG_VALUE(FlagStaticMember, 1 << 12); +ASSERT_DIFLAG_VALUE(FlagLValueReference, 1 << 13); +ASSERT_DIFLAG_VALUE(FlagRValueReference, 1 << 14); +// Bit (1 << 15) has been recycled, but the C API value hasn't been renamed. +static_assert((LLVMDIFlagReserved == (1 << 15)) && + (DINode::DIFlags::FlagExportSymbols == (1 << 15))); +ASSERT_DIFLAG_VALUE(FlagSingleInheritance, 1 << 16); +ASSERT_DIFLAG_VALUE(FlagMultipleInheritance, 2 << 16); +ASSERT_DIFLAG_VALUE(FlagVirtualInheritance, 3 << 16); +// Bit (1 << 17) is part of the inheritance values above. +ASSERT_DIFLAG_VALUE(FlagIntroducedVirtual, 1 << 18); +ASSERT_DIFLAG_VALUE(FlagBitField, 1 << 19); +ASSERT_DIFLAG_VALUE(FlagNoReturn, 1 << 20); +// Bit (1 << 21) is unused, but was `LLVMDIFlagMainSubprogram`. +ASSERT_DIFLAG_VALUE(FlagTypePassByValue, 1 << 22); +ASSERT_DIFLAG_VALUE(FlagTypePassByReference, 1 << 23); +ASSERT_DIFLAG_VALUE(FlagEnumClass, 1 << 24); +ASSERT_DIFLAG_VALUE(FlagThunk, 1 << 25); +ASSERT_DIFLAG_VALUE(FlagNonTrivial, 1 << 26); +ASSERT_DIFLAG_VALUE(FlagBigEndian, 1 << 27); +ASSERT_DIFLAG_VALUE(FlagLittleEndian, 1 << 28); +ASSERT_DIFLAG_VALUE(FlagIndirectVirtualBase, (1 << 2) | (1 << 5)); +#undef ASSERT_DIFLAG_VALUE + +// There are two potential ways to convert `LLVMDIFlags` to `DIFlags`: +// - Check and copy every individual bit/subvalue from input to output. +// - Statically assert that both have the same layout, and cast. +// As long as the static assertions succeed, a cast is easier and faster. +// In the (hopefully) unlikely event that the assertions do fail someday, and +// LLVM doesn't expose its own conversion function, we'll have to switch over +// to copying each bit/subvalue. +static DINode::DIFlags fromRust(LLVMDIFlags Flags) { + // Check that all set bits are covered by the static assertions above. + const unsigned UNKNOWN_BITS = (1 << 31) | (1 << 30) | (1 << 29) | (1 << 21); + if (Flags & UNKNOWN_BITS) { + report_fatal_error("bad LLVMDIFlags"); + } + + // As long as the static assertions are satisfied and no unknown bits are + // present, we can convert from `LLVMDIFlags` to `DIFlags` with a cast. + return static_cast<DINode::DIFlags>(Flags); } // These values **must** match debuginfo::DISPFlags! They also *happen* diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index 6512176cc4a..a6db12f8932 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -417,7 +417,8 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { // Any descendants of `std` should be private. These crates are usually not marked // private in metadata, so we ignore that field. if extern_private.is_none() - && dep_root.map_or(false, |d| STDLIB_STABLE_CRATES.contains(&d.name)) + && let Some(dep) = dep_root + && STDLIB_STABLE_CRATES.contains(&dep.name) { return true; } diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 5d78bed5cf8..926760b84aa 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -12,7 +12,7 @@ use rustc_hir::*; use rustc_hir_pretty as pprust_hir; use rustc_middle::hir::nested_filter; use rustc_span::def_id::StableCrateId; -use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym}; +use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, kw, sym, with_metavar_spans}; use crate::hir::ModuleItems; use crate::middle::debugger_visualizer::DebuggerVisualizerFile; @@ -1117,6 +1117,9 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { // the fly in the resolver, storing only their accumulated hash in `ResolverGlobalCtxt`, // and combining it with other hashes here. resolutions.visibilities_for_hashing.hash_stable(&mut hcx, &mut stable_hasher); + with_metavar_spans(|mspans| { + mspans.freeze_and_get_read_spans().hash_stable(&mut hcx, &mut stable_hasher); + }); stable_hasher.finish() }); diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 1231ea88569..60e1ff1d049 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -467,9 +467,6 @@ impl<'tcx> Const<'tcx> { let const_val = tcx.valtree_to_const_val((ty, valtree)); Self::Val(const_val, ty) } - ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, args }) => { - Self::Unevaluated(UnevaluatedConst { def, args, promoted: None }, ty) - } _ => Self::Ty(ty, c), } } diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs index cd6b2d65bf1..65f51ae9d39 100644 --- a/compiler/rustc_middle/src/mir/coverage.rs +++ b/compiler/rustc_middle/src/mir/coverage.rs @@ -71,11 +71,7 @@ impl ConditionId { /// Enum that can hold a constant zero value, the ID of an physical coverage /// counter, or the ID of a coverage-counter expression. -/// -/// This was originally only used for expression operands (and named `Operand`), -/// but the zero/counter/expression distinction is also useful for representing -/// the value of code/gap mappings, and the true/false arms of branch mappings. -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub enum CovTerm { Zero, @@ -171,7 +167,7 @@ impl Op { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] #[derive(TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)] pub struct Expression { pub lhs: CovTerm, diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index d6f8fed755f..1b07846e0cf 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -222,7 +222,7 @@ impl AllocError { } /// The information that makes up a memory access: offset and size. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub struct AllocRange { pub start: Size, pub size: Size, diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 3a83b184d83..78196b05361 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -97,7 +97,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { debug_assert!(prov.len() <= 1); if let Some(entry) = prov.first() { // If it overlaps with this byte, it is on this byte. - debug_assert!(self.bytes.as_ref().map_or(true, |b| b.get(&offset).is_none())); + debug_assert!(self.bytes.as_ref().is_none_or(|b| !b.contains_key(&offset))); Some(entry.1) } else { // Look up per-byte provenance. @@ -301,7 +301,7 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { // For really small copies, make sure we don't start before `src` does. let entry_start = cmp::max(entry.0, src.start); for offset in entry_start..src.end() { - if bytes.last().map_or(true, |bytes_entry| bytes_entry.0 < offset) { + if bytes.last().is_none_or(|bytes_entry| bytes_entry.0 < offset) { // The last entry, if it exists, has a lower offset than us. bytes.push((offset, entry.1)); } else { diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 24d2478f770..ea35323ccc7 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1068,6 +1068,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { pretty_print_const(b, fmt, false)?; write!(fmt, "]") } + Len(ref a) => write!(fmt, "Len({a:?})"), Cast(ref kind, ref place, ref ty) => { with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})")) } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 470a247d794..609d5647d04 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -424,6 +424,7 @@ impl<'tcx> Rvalue<'tcx> { | Rvalue::Ref(_, _, _) | Rvalue::ThreadLocalRef(_) | Rvalue::RawPtr(_, _) + | Rvalue::Len(_) | Rvalue::Cast( CastKind::IntToInt | CastKind::FloatToInt diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index bbbaffc5a35..0c17a2e0fe5 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1351,6 +1351,16 @@ pub enum Rvalue<'tcx> { /// model. RawPtr(Mutability, Place<'tcx>), + /// Yields the length of the place, as a `usize`. + /// + /// If the type of the place is an array, this is the array length. For slices (`[T]`, not + /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is + /// ill-formed for places of other types. + /// + /// This cannot be a `UnOp(PtrMetadata, _)` because that expects a value, and we only + /// have a place, and `UnOp(PtrMetadata, RawPtr(place))` is not a thing. + Len(Place<'tcx>), + /// Performs essentially all of the casts that can be performed via `as`. /// /// This allows for casts from/to a variety of types. diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index cbb26b83c79..db77017310a 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -210,6 +210,7 @@ impl<'tcx> Rvalue<'tcx> { let place_ty = place.ty(local_decls, tcx).ty; Ty::new_ptr(tcx, place_ty, mutability) } + Rvalue::Len(..) => tcx.types.usize, Rvalue::Cast(.., ty) => ty, Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => { let lhs_ty = lhs.ty(local_decls, tcx); diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 12a024a219e..058acbd4024 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -695,6 +695,14 @@ macro_rules! make_mir_visitor { self.visit_place(path, ctx, location); } + Rvalue::Len(path) => { + self.visit_place( + path, + PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), + location + ); + } + Rvalue::Cast(_cast_kind, operand, ty) => { self.visit_operand(operand, location); self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); diff --git a/compiler/rustc_middle/src/query/arena_cached.rs b/compiler/rustc_middle/src/query/arena_cached.rs new file mode 100644 index 00000000000..ec6e466ff68 --- /dev/null +++ b/compiler/rustc_middle/src/query/arena_cached.rs @@ -0,0 +1,47 @@ +/// Helper trait that allows `arena_cache` queries to return `Option<&T>` +/// instead of `&Option<T>`, and avoid allocating `None` in the arena. +/// +/// An arena-cached query must be declared to return a type that implements +/// this trait, i.e. either `&'tcx T` or `Option<&'tcx T>`. This trait then +/// determines the types returned by the provider and stored in the arena, +/// and provides a function to bridge between the three types. +pub trait ArenaCached<'tcx>: Sized { + /// Type that is returned by the query provider. + type Provided; + /// Type that is stored in the arena. + type Allocated: 'tcx; + + /// Takes a provided value, and allocates it in the arena (if appropriate) + /// with the help of the given `arena_alloc` closure. + fn alloc_in_arena( + arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated, + value: Self::Provided, + ) -> Self; +} + +impl<'tcx, T> ArenaCached<'tcx> for &'tcx T { + type Provided = T; + type Allocated = T; + + fn alloc_in_arena( + arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated, + value: Self::Provided, + ) -> Self { + // Just allocate in the arena normally. + arena_alloc(value) + } +} + +impl<'tcx, T> ArenaCached<'tcx> for Option<&'tcx T> { + type Provided = Option<T>; + /// The provide value is `Option<T>`, but we only store `T` in the arena. + type Allocated = T; + + fn alloc_in_arena( + arena_alloc: impl Fn(Self::Allocated) -> &'tcx Self::Allocated, + value: Self::Provided, + ) -> Self { + // Don't store None in the arena, and wrap the allocated reference in Some. + value.map(arena_alloc) + } +} diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index bfbcb0532c1..05ded71dbeb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -7,7 +7,6 @@ #![allow(unused_parens)] use std::mem; -use std::ops::Deref; use std::path::PathBuf; use std::sync::Arc; @@ -85,6 +84,7 @@ use crate::ty::{ }; use crate::{dep_graph, mir, thir}; +mod arena_cached; pub mod erase; mod keys; pub use keys::{AsLocalKey, Key, LocalCrate}; @@ -586,7 +586,7 @@ rustc_queries! { separate_provide_extern } - query mir_coroutine_witnesses(key: DefId) -> &'tcx Option<mir::CoroutineLayout<'tcx>> { + query mir_coroutine_witnesses(key: DefId) -> Option<&'tcx mir::CoroutineLayout<'tcx>> { arena_cache desc { |tcx| "coroutine witness types for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -1164,8 +1164,7 @@ rustc_queries! { } /// Check whether the function has any recursion that could cause the inliner to trigger - /// a cycle. Returns the call stack causing the cycle. The call stack does not contain the - /// current function, just all intermediate functions. + /// a cycle. query mir_callgraph_reachable(key: (ty::Instance<'tcx>, LocalDefId)) -> bool { fatal_cycle desc { |tcx| @@ -2416,7 +2415,7 @@ rustc_queries! { /// because the `ty::Ty`-based wfcheck is always run. query diagnostic_hir_wf_check( key: (ty::Predicate<'tcx>, WellFormedLoc) - ) -> &'tcx Option<ObligationCause<'tcx>> { + ) -> Option<&'tcx ObligationCause<'tcx>> { arena_cache eval_always no_hash diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 2cb6f6d8c6e..1c157f33a81 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -289,10 +289,10 @@ macro_rules! define_callbacks { /// This type alias specifies the type returned from query providers and the type /// used for decoding. For regular queries this is the declared returned type `V`, - /// but `arena_cache` will use `<V as Deref>::Target` instead. + /// but `arena_cache` will use `<V as ArenaCached>::Provided` instead. pub type ProvidedValue<'tcx> = query_if_arena!( [$($modifiers)*] - (<$V as Deref>::Target) + (<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Provided) ($V) ); @@ -307,10 +307,18 @@ macro_rules! define_callbacks { ) -> Erase<Value<'tcx>> { erase(query_if_arena!([$($modifiers)*] { - if mem::needs_drop::<ProvidedValue<'tcx>>() { - &*_tcx.query_system.arenas.$name.alloc(value) + use $crate::query::arena_cached::ArenaCached; + + if mem::needs_drop::<<$V as ArenaCached<'tcx>>::Allocated>() { + <$V as ArenaCached>::alloc_in_arena( + |v| _tcx.query_system.arenas.$name.alloc(v), + value, + ) } else { - &*_tcx.arena.dropless.alloc(value) + <$V as ArenaCached>::alloc_in_arena( + |v| _tcx.arena.dropless.alloc(v), + value, + ) } } (value) @@ -354,7 +362,7 @@ macro_rules! define_callbacks { pub struct QueryArenas<'tcx> { $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*] - (TypedArena<<$V as Deref>::Target>) + (TypedArena<<$V as $crate::query::arena_cached::ArenaCached<'tcx>>::Allocated>) () ),)* } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index db2bb8a7248..55d78e083e0 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -345,9 +345,6 @@ pub enum ObligationCauseCode<'tcx> { /// `main` has wrong type MainFunctionType, - /// `start` has wrong type - StartFunctionType, - /// language function has wrong type LangFunctionType(Symbol), diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 33d39b137b6..c4d5367e2f0 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -433,7 +433,7 @@ pub fn analyze_coroutine_closure_captures<'a, 'tcx: 'a, T>( // A parent matches a child if they share the same prefix of projections. // The child may have more, if it is capturing sub-fields out of // something that is captured by-move in the parent closure. - while child_captures.peek().map_or(false, |(_, child_capture)| { + while child_captures.peek().is_some_and(|(_, child_capture)| { child_prefix_matches_parent_projections(parent_capture, child_capture) }) { let (child_field_idx, child_capture) = child_captures.next().unwrap(); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 7035e641f39..2d76f6ec7d6 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -52,7 +52,9 @@ use rustc_type_ir::TyKind::*; use rustc_type_ir::fold::TypeFoldable; use rustc_type_ir::lang_items::TraitSolverLangItem; pub use rustc_type_ir::lift::Lift; -use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, search_graph}; +use rustc_type_ir::{ + CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo, elaborate, search_graph, +}; use tracing::{debug, instrument}; use crate::arena::Arena; @@ -2558,7 +2560,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` /// returns true if the `trait_def_id` defines an associated item of name `assoc_name`. pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool { - self.supertrait_def_ids(trait_def_id).any(|trait_did| { + elaborate::supertrait_def_ids(self, trait_def_id).any(|trait_did| { self.associated_items(trait_did) .filter_by_name_unhygienic(assoc_name.name) .any(|item| self.hygienic_eq(assoc_name, item.ident(self), trait_did)) @@ -2579,14 +2581,6 @@ impl<'tcx> TyCtxt<'tcx> { }) } - /// Computes the def-ids of the transitive supertraits of `trait_def_id`. This (intentionally) - /// does not compute the full elaborated super-predicates but just the set of def-ids. It is used - /// to identify which traits may define a given associated type to help avoid cycle errors, - /// and to make size estimates for vtable layout computation. - pub fn supertrait_def_ids(self, trait_def_id: DefId) -> impl Iterator<Item = DefId> + 'tcx { - rustc_type_ir::elaborate::supertrait_def_ids(self, trait_def_id) - } - /// Given a closure signature, returns an equivalent fn signature. Detuples /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then /// you would get a `fn(u32, i32)`. diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 77745599afb..e4187d2760c 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -336,7 +336,7 @@ pub fn suggest_constraining_type_params<'a>( .collect(); constraints - .retain(|(_, def_id, _)| def_id.map_or(true, |def| !bound_trait_defs.contains(&def))); + .retain(|(_, def_id, _)| def_id.is_none_or(|def| !bound_trait_defs.contains(&def))); if constraints.is_empty() { continue; diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index e4ded2c30f5..b7a648aae3f 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -328,7 +328,7 @@ impl<'tcx> InstanceKind<'tcx> { // We include enums without destructors to allow, say, optimizing // drops of `Option::None` before LTO. We also respect the intent of // `#[inline]` on `Drop::drop` implementations. - return ty.ty_adt_def().map_or(true, |adt_def| { + return ty.ty_adt_def().is_none_or(|adt_def| { match *self { ty::InstanceKind::DropGlue(..) => adt_def.destructor(tcx).map(|dtor| dtor.did), ty::InstanceKind::AsyncDropGlueCtorShim(..) => { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d2875fb3794..ca70ae794c5 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -79,8 +79,7 @@ pub use self::predicate::{ PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate, - RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, TraitPredicate, TraitRef, - TypeOutlivesPredicate, + RegionOutlivesPredicate, SubtypePredicate, TraitPredicate, TraitRef, TypeOutlivesPredicate, }; pub use self::region::{ BoundRegion, BoundRegionKind, EarlyParamRegion, LateParamRegion, LateParamRegionKind, Region, diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 32d6455e825..584cac22ae8 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -476,16 +476,6 @@ impl<'tcx> Clause<'tcx> { } } -pub trait ToPolyTraitRef<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>; -} - -impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> { - fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> { - self.map_bound_ref(|trait_pred| trait_pred.trait_ref) - } -} - impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PredicateKind<'tcx>> for Predicate<'tcx> { fn upcast_from(from: PredicateKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self { ty::Binder::dummy(from).upcast(tcx) diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index bf37ae05c82..a9a47c87a38 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1894,11 +1894,11 @@ impl<'tcx> Ty<'tcx> { ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::Dyn) | ty::Foreign(..) => false, - ty::Tuple(tys) => tys.last().map_or(true, |ty| ty.is_trivially_sized(tcx)), + ty::Tuple(tys) => tys.last().is_none_or(|ty| ty.is_trivially_sized(tcx)), ty::Adt(def, args) => def .sized_constraint(tcx) - .map_or(true, |ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)), + .is_none_or(|ty| ty.instantiate(tcx, args).is_trivially_sized(tcx)), ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) | ty::Bound(..) => false, diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 09a05104e49..23e2e8ad3d3 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -2,6 +2,7 @@ use std::fmt; use rustc_ast::Mutability; use rustc_macros::HashStable; +use rustc_type_ir::elaborate; use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range}; use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt}; @@ -64,7 +65,7 @@ pub(crate) fn vtable_min_entries<'tcx>( }; // This includes self in supertraits. - for def_id in tcx.supertrait_def_ids(trait_ref.def_id()) { + for def_id in elaborate::supertrait_def_ids(tcx, trait_ref.def_id()) { count += tcx.own_existential_vtable_entries(def_id).len(); } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 390909bb0ab..9120a248d95 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -360,7 +360,7 @@ fn find_item_ty_spans( if let Res::Def(kind, def_id) = path.res && matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union) { - let check_params = def_id.as_local().map_or(true, |def_id| { + let check_params = def_id.as_local().is_none_or(|def_id| { if def_id == needle { spans.push(ty.span); } diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 5203c33c968..ffdb721fb18 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -118,12 +118,6 @@ mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed = .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior .label = use of extern static -mir_build_force_inline = - `{$callee}` is incompatible with `#[rustc_force_inline]` - .attr = annotation here - .callee = `{$callee}` defined here - .note = incompatible due to: {$reason} - mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant mir_build_initializing_type_with_requires_unsafe = @@ -330,12 +324,6 @@ mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/s mir_build_type_not_structural_tip = the `PartialEq` trait must be derived, manual `impl`s are not sufficient; see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details -mir_build_unconditional_recursion = function cannot return without recursing - .label = cannot return without recursing - .help = a `loop` may express intention better if this is on purpose - -mir_build_unconditional_recursion_call_site_label = recursive call site - mir_build_union_field_requires_unsafe = access to union field is unsafe and requires unsafe block .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 3dd5de02230..59f440432eb 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -246,6 +246,7 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let offset = self.parse_operand(args[1])?; Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset)))) }, + @call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)), @call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)), @call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)), ExprKind::Borrow { borrow_kind, arg } => Ok( diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 89c7bb357ef..b1851e79d5c 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::*; use rustc_middle::thir::*; use rustc_middle::ty::{self, AdtDef, CanonicalUserTypeAnnotation, Ty, Variance}; use rustc_middle::{bug, span_bug}; -use rustc_span::{DesugaringKind, Span}; +use rustc_span::Span; use tracing::{debug, instrument, trace}; use crate::builder::ForGuard::{OutsideGuard, RefWithinGuard}; @@ -630,98 +630,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(base_place.index(idx)) } - /// Given a place that's either an array or a slice, returns an operand - /// with the length of the array/slice. - /// - /// For arrays it'll be `Operand::Constant` with the actual length; - /// For slices it'll be `Operand::Move` of a local using `PtrMetadata`. - pub(in crate::builder) fn len_of_slice_or_array( - &mut self, - block: BasicBlock, - place: Place<'tcx>, - span: Span, - source_info: SourceInfo, - ) -> Operand<'tcx> { - let place_ty = place.ty(&self.local_decls, self.tcx).ty; - let usize_ty = self.tcx.types.usize; - - match place_ty.kind() { - ty::Array(_elem_ty, len_const) => { - let ty_const = if let Some((_, len_ty)) = len_const.try_to_valtree() - && len_ty != self.tcx.types.usize - { - // Bad const generics can give us a constant from the type that's - // not actually a `usize`, so in that case give an error instead. - // FIXME: It'd be nice if the type checker made sure this wasn't - // possible, instead. - let err = self.tcx.dcx().span_delayed_bug( - span, - format!( - "Array length should have already been a type error, as it's {len_ty:?}" - ), - ); - ty::Const::new_error(self.tcx, err) - } else { - // We know how long an array is, so just use that as a constant - // directly -- no locals needed. We do need one statement so - // that borrow- and initialization-checking consider it used, - // though. FIXME: Do we really *need* to count this as a use? - // Could partial array tracking work off something else instead? - self.cfg.push_fake_read(block, source_info, FakeReadCause::ForIndex, place); - *len_const - }; - - let const_ = Const::from_ty_const(ty_const, usize_ty, self.tcx); - Operand::Constant(Box::new(ConstOperand { span, user_ty: None, const_ })) - } - ty::Slice(_elem_ty) => { - let ptr_or_ref = if let [PlaceElem::Deref] = place.projection[..] - && let local_ty = self.local_decls[place.local].ty - && local_ty.is_trivially_pure_clone_copy() - { - // It's extremely common that we have something that can be - // directly passed to `PtrMetadata`, so avoid an unnecessary - // temporary and statement in those cases. Note that we can - // only do that for `Copy` types -- not `&mut [_]` -- because - // the MIR we're building here needs to pass NLL later. - Operand::Copy(Place::from(place.local)) - } else { - let len_span = self.tcx.with_stable_hashing_context(|hcx| { - let span = source_info.span; - span.mark_with_reason( - None, - DesugaringKind::IndexBoundsCheckReborrow, - span.edition(), - hcx, - ) - }); - let ptr_ty = Ty::new_imm_ptr(self.tcx, place_ty); - let slice_ptr = self.temp(ptr_ty, span); - self.cfg.push_assign( - block, - SourceInfo { span: len_span, ..source_info }, - slice_ptr, - Rvalue::RawPtr(Mutability::Not, place), - ); - Operand::Move(slice_ptr) - }; - - let len = self.temp(usize_ty, span); - self.cfg.push_assign( - block, - source_info, - len, - Rvalue::UnaryOp(UnOp::PtrMetadata, ptr_or_ref), - ); - - Operand::Move(len) - } - _ => { - span_bug!(span, "len called on place of type {place_ty:?}") - } - } - } - fn bounds_check( &mut self, block: BasicBlock, @@ -730,25 +638,25 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr_span: Span, source_info: SourceInfo, ) -> BasicBlock { - let slice = slice.to_place(self); + let usize_ty = self.tcx.types.usize; + let bool_ty = self.tcx.types.bool; + // bounds check: + let len = self.temp(usize_ty, expr_span); + let lt = self.temp(bool_ty, expr_span); // len = len(slice) - let len = self.len_of_slice_or_array(block, slice, expr_span, source_info); - + self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice.to_place(self))); // lt = idx < len - let bool_ty = self.tcx.types.bool; - let lt = self.temp(bool_ty, expr_span); self.cfg.push_assign( block, source_info, lt, Rvalue::BinaryOp( BinOp::Lt, - Box::new((Operand::Copy(Place::from(index)), len.to_copy())), + Box::new((Operand::Copy(Place::from(index)), Operand::Copy(len))), ), ); - let msg = BoundsCheck { len, index: Operand::Copy(Place::from(index)) }; - + let msg = BoundsCheck { len: Operand::Move(len), index: Operand::Copy(Place::from(index)) }; // assert!(lt, "...") self.assert(block, Operand::Move(lt), true, msg, expr_span) } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index b944d13fb0d..b21ec8f3083 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1986,6 +1986,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { return; } + let false_edge_start_block = candidate.subcandidates[0].false_edge_start_block; candidate.subcandidates.retain_mut(|candidate| { if candidate.extra_data.is_never { candidate.visit_leaves(|subcandidate| { @@ -2000,8 +2001,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } }); if candidate.subcandidates.is_empty() { - // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`. - candidate.pre_binding_block = Some(self.cfg.start_new_block()); + // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block` and `otherwise_block`. + let next_block = self.cfg.start_new_block(); + candidate.pre_binding_block = Some(next_block); + candidate.otherwise_block = Some(next_block); + // In addition, if `candidate` doesn't have `false_edge_start_block`, it should be assigned here. + if candidate.false_edge_start_block.is_none() { + candidate.false_edge_start_block = false_edge_start_block; + } } } diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 0d36b7bb3ee..8cca84d7fcc 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -243,8 +243,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } TestKind::Len { len, op } => { + let usize_ty = self.tcx.types.usize; + let actual = self.temp(usize_ty, test.span); + // actual = len(place) - let actual = self.len_of_slice_or_array(block, place, test.span, source_info); + self.cfg.push_assign(block, source_info, actual, Rvalue::Len(place)); // expected = <N> let expected = self.push_usize(block, source_info, len); @@ -259,7 +262,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fail_block, source_info, op, - actual, + Operand::Move(actual), Operand::Move(expected), ); } diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 8b01ec0d06a..9fa431f7d5f 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -26,10 +26,8 @@ use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt, TypeVisitableExt, TypingMode use rustc_middle::{bug, span_bug}; use rustc_span::{Span, Symbol, sym}; -use super::lints; use crate::builder::expr::as_place::PlaceBuilder; use crate::builder::scope::DropKind; -use crate::check_inline; pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( tcx: TyCtxt<'tcx>, @@ -48,7 +46,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( } /// Construct the MIR for a given `DefId`. -pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> { +pub(crate) fn build_mir<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx> { let tcx = tcx.tcx; tcx.ensure_with_value().thir_abstract_const(def); if let Err(e) = tcx.check_match(def) { @@ -80,9 +78,6 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx } }; - lints::check(tcx, &body); - check_inline::check_force_inline(tcx, &body); - // The borrow checker will replace all the regions here with its own // inference variables. There's no point having non-erased regions here. // The exception is `body.user_type_annotations`, which is used unmodified diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 5eed9ef798d..995bc311b7c 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -266,7 +266,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for LayoutConstrainedPlaceVisitor<'a, 'tcx> { // place, i.e. the expression is a place expression and not a dereference // (since dereferencing something leads us to a different place). ExprKind::Deref { .. } => {} - ref kind if ExprCategory::of(kind).map_or(true, |cat| cat == ExprCategory::Place) => { + ref kind if ExprCategory::of(kind).is_none_or(|cat| cat == ExprCategory::Place) => { visit::walk_expr(self, expr); } diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 90c31a2caa3..83aec9ccdef 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -12,16 +12,6 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; #[derive(LintDiagnostic)] -#[diag(mir_build_unconditional_recursion)] -#[help] -pub(crate) struct UnconditionalRecursion { - #[label] - pub(crate) span: Span, - #[label(mir_build_unconditional_recursion_call_site_label)] - pub(crate) call_sites: Vec<Span>, -} - -#[derive(LintDiagnostic)] #[diag(mir_build_call_to_deprecated_safe_fn_requires_unsafe)] pub(crate) struct CallToDeprecatedSafeFnRequiresUnsafe { #[label] @@ -1107,15 +1097,3 @@ impl<'a> Subdiagnostic for Rust2024IncompatiblePatSugg<'a> { ); } } - -#[derive(Diagnostic)] -#[diag(mir_build_force_inline)] -#[note] -pub(crate) struct InvalidForceInline { - #[primary_span] - pub attr_span: Span, - #[label(mir_build_callee)] - pub callee_span: Span, - pub callee: String, - pub reason: &'static str, -} diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 76a35355de7..8e786733ee0 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -15,11 +15,9 @@ // "Go to file" feature to silently ignore all files in the module, probably // because it assumes that "build" is a build-output directory. See #134365. mod builder; -pub mod check_inline; mod check_tail_calls; mod check_unsafety; mod errors; -pub mod lints; mod thir; use rustc_middle::util::Providers; @@ -29,7 +27,7 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { providers.check_match = thir::pattern::check_match; providers.lit_to_const = thir::constant::lit_to_const; - providers.hooks.build_mir = builder::mir_build; + providers.hooks.build_mir = builder::build_mir; providers.closure_saved_names_of_captured_variables = builder::closure_saved_names_of_captured_variables; providers.check_unsafety = check_unsafety::check_unsafety; diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index a13b00e1921..b5b7b54a1cc 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1086,14 +1086,13 @@ fn find_fallback_pattern_typo<'tcx>( let vis = cx.tcx.visibility(item.owner_id); if vis.is_accessible_from(parent, cx.tcx) { accessible.push(item_name); - let path = if item_name == name { - // We know that the const wasn't in scope because it has the exact - // same name, so we suggest the full path. - with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id)) - } else { - // The const is likely just typoed, and nothing else. - cx.tcx.def_path_str(item.owner_id) - }; + // FIXME: the line below from PR #135310 is a workaround for the ICE in issue + // #135289, where a macro in a dependency can create unreachable patterns in the + // current crate. Path trimming expects diagnostics for a typoed const, but no + // diagnostics are emitted and we ICE. See + // `tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs` for a + // test that reproduces the ICE if we don't use `with_no_trimmed_paths!`. + let path = with_no_trimmed_paths!(cx.tcx.def_path_str(item.owner_id)); accessible_path.push(path); } else if name == item_name { // The const exists somewhere in this crate, but it can't be imported diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs index e457b514936..9ccabb46c63 100644 --- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs +++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs @@ -608,7 +608,7 @@ where let before = diffs_before.as_mut().map(next_in_dataflow_order); assert!(diffs_after.is_empty()); - assert!(diffs_before.as_ref().map_or(true, ExactSizeIterator::is_empty)); + assert!(diffs_before.as_ref().is_none_or(ExactSizeIterator::is_empty)); let terminator = self.cursor.body()[block].terminator(); let mut terminator_str = String::new(); diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index f2ef5018c49..df4b1a53417 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -91,6 +91,7 @@ where | Rvalue::Use(..) | Rvalue::ThreadLocalRef(..) | Rvalue::Repeat(..) + | Rvalue::Len(..) | Rvalue::BinaryOp(..) | Rvalue::NullaryOp(..) | Rvalue::UnaryOp(..) diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 80875f32e4f..d1b3a389e9e 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -413,6 +413,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { Rvalue::Ref(..) | Rvalue::RawPtr(..) | Rvalue::Discriminant(..) + | Rvalue::Len(..) | Rvalue::NullaryOp( NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..) | NullOp::UbChecks, _, diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index b0c023cca82..5628f4c9381 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -27,6 +27,12 @@ mir_transform_force_inline = .callee = `{$callee}` defined here .note = could not be inlined due to: {$reason} +mir_transform_force_inline_attr = + `{$callee}` is incompatible with `#[rustc_force_inline]` + .attr = annotation here + .callee = `{$callee}` defined here + .note = incompatible due to: {$reason} + mir_transform_force_inline_justification = `{$callee}` is required to be inlined to: {$sym} @@ -66,6 +72,12 @@ mir_transform_unaligned_packed_ref = reference to packed field is unaligned .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced) .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers) +mir_transform_unconditional_recursion = function cannot return without recursing + .label = cannot return without recursing + .help = a `loop` may express intention better if this is on purpose + +mir_transform_unconditional_recursion_call_site_label = recursive call site + mir_transform_undefined_transmute = pointers cannot be transmuted to integers during const eval .note = at compile-time, pointers do not have an integer value .note2 = avoiding this restriction via `union` or raw pointers leads to compile-time undefined behavior diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs index 5cf33868ade..51fd3c6512e 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs @@ -10,25 +10,54 @@ use rustc_session::lint::builtin::UNCONDITIONAL_RECURSION; use rustc_span::Span; use crate::errors::UnconditionalRecursion; +use crate::pass_manager::MirLint; -pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - check_call_recursion(tcx, body); +pub(super) struct CheckCallRecursion; + +impl<'tcx> MirLint<'tcx> for CheckCallRecursion { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id().expect_local(); + + if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) { + // If this is trait/impl method, extract the trait's args. + let trait_args = match tcx.trait_of_item(def_id.to_def_id()) { + Some(trait_def_id) => { + let trait_args_count = tcx.generics_of(trait_def_id).count(); + &GenericArgs::identity_for_item(tcx, def_id)[..trait_args_count] + } + _ => &[], + }; + + check_recursion(tcx, body, CallRecursion { trait_args }) + } + } } -fn check_call_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let def_id = body.source.def_id().expect_local(); +/// Requires drop elaboration to have been performed. +pub(super) struct CheckDropRecursion; - if let DefKind::Fn | DefKind::AssocFn = tcx.def_kind(def_id) { - // If this is trait/impl method, extract the trait's args. - let trait_args = match tcx.trait_of_item(def_id.to_def_id()) { - Some(trait_def_id) => { - let trait_args_count = tcx.generics_of(trait_def_id).count(); - &GenericArgs::identity_for_item(tcx, def_id)[..trait_args_count] - } - _ => &[], - }; +impl<'tcx> MirLint<'tcx> for CheckDropRecursion { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id().expect_local(); - check_recursion(tcx, body, CallRecursion { trait_args }) + // First check if `body` is an `fn drop()` of `Drop` + if let DefKind::AssocFn = tcx.def_kind(def_id) + && let Some(trait_ref) = + tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) + && let Some(drop_trait) = tcx.lang_items().drop_trait() + && drop_trait == trait_ref.instantiate_identity().def_id + // avoid erroneous `Drop` impls from causing ICEs below + && let sig = tcx.fn_sig(def_id).instantiate_identity() + && sig.inputs().skip_binder().len() == 1 + { + // It was. Now figure out for what type `Drop` is implemented and then + // check for recursion. + if let ty::Ref(_, dropped_ty, _) = + tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind() + { + check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); + } + } } } @@ -61,30 +90,6 @@ fn check_recursion<'tcx>( } } -/// Requires drop elaboration to have been performed first. -pub fn check_drop_recursion<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let def_id = body.source.def_id().expect_local(); - - // First check if `body` is an `fn drop()` of `Drop` - if let DefKind::AssocFn = tcx.def_kind(def_id) - && let Some(trait_ref) = - tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id)) - && let Some(drop_trait) = tcx.lang_items().drop_trait() - && drop_trait == trait_ref.instantiate_identity().def_id - // avoid erroneous `Drop` impls from causing ICEs below - && let sig = tcx.fn_sig(def_id).instantiate_identity() - && sig.inputs().skip_binder().len() == 1 - { - // It was. Now figure out for what type `Drop` is implemented and then - // check for recursion. - if let ty::Ref(_, dropped_ty, _) = - tcx.liberate_late_bound_regions(def_id.to_def_id(), sig.input(0)).kind() - { - check_recursion(tcx, body, RecursiveDrop { drop_for: *dropped_ty }); - } - } -} - trait TerminatorClassifier<'tcx> { fn is_recursive_terminator( &self, diff --git a/compiler/rustc_mir_build/src/check_inline.rs b/compiler/rustc_mir_transform/src/check_inline.rs index 1af3b3e2c13..497f4a660ea 100644 --- a/compiler/rustc_mir_build/src/check_inline.rs +++ b/compiler/rustc_mir_transform/src/check_inline.rs @@ -1,3 +1,6 @@ +//! Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its +//! definition alone (irrespective of any specific caller). + use rustc_attr_parsing::InlineAttr; use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; @@ -6,30 +9,37 @@ use rustc_middle::ty; use rustc_middle::ty::TyCtxt; use rustc_span::sym; -/// Check that a body annotated with `#[rustc_force_inline]` will not fail to inline based on its -/// definition alone (irrespective of any specific caller). -pub(crate) fn check_force_inline<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { - let def_id = body.source.def_id(); - if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() { - return; - } - let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else { - return; - }; +use crate::pass_manager::MirLint; - if let Err(reason) = - is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body)) - { - tcx.dcx().emit_err(crate::errors::InvalidForceInline { - attr_span, - callee_span: tcx.def_span(def_id), - callee: tcx.def_path_str(def_id), - reason, - }); +pub(super) struct CheckForceInline; + +impl<'tcx> MirLint<'tcx> for CheckForceInline { + fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { + let def_id = body.source.def_id(); + if !tcx.hir().body_owner_kind(def_id).is_fn_or_closure() || !def_id.is_local() { + return; + } + let InlineAttr::Force { attr_span, .. } = tcx.codegen_fn_attrs(def_id).inline else { + return; + }; + + if let Err(reason) = + is_inline_valid_on_fn(tcx, def_id).and_then(|_| is_inline_valid_on_body(tcx, body)) + { + tcx.dcx().emit_err(crate::errors::InvalidForceInline { + attr_span, + callee_span: tcx.def_span(def_id), + callee: tcx.def_path_str(def_id), + reason, + }); + } } } -pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<(), &'static str> { +pub(super) fn is_inline_valid_on_fn<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> Result<(), &'static str> { let codegen_attrs = tcx.codegen_fn_attrs(def_id); if tcx.has_attr(def_id, sym::rustc_no_mir_inline) { return Err("#[rustc_no_mir_inline]"); @@ -65,7 +75,7 @@ pub fn is_inline_valid_on_fn<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result<( Ok(()) } -pub fn is_inline_valid_on_body<'tcx>( +pub(super) fn is_inline_valid_on_body<'tcx>( _: TyCtxt<'tcx>, body: &Body<'tcx>, ) -> Result<(), &'static str> { diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 1a9323329f6..8d397f63cc7 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -1,10 +1,9 @@ use std::cmp::Ordering; -use std::fmt::{self, Debug}; use either::Either; use itertools::Itertools; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::graph::DirectedGraph; use rustc_index::IndexVec; use rustc_index::bit_set::DenseBitSet; @@ -20,134 +19,163 @@ mod iter_nodes; mod node_flow; mod union_find; -/// The coverage counter or counter expression associated with a particular -/// BCB node or BCB edge. -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -enum BcbCounter { - Counter { id: CounterId }, - Expression { id: ExpressionId }, +/// Ensures that each BCB node needing a counter has one, by creating physical +/// counters or counter expressions for nodes as required. +pub(super) fn make_bcb_counters( + graph: &CoverageGraph, + bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>, +) -> CoverageCounters { + // Create the derived graphs that are necessary for subsequent steps. + let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable); + let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph); + + // Use those graphs to determine which nodes get physical counters, and how + // to compute the execution counts of other nodes from those counters. + let nodes = make_node_counter_priority_list(graph, balanced_graph); + let node_counters = merged_graph.make_node_counters(&nodes); + + // Convert the counters into a form suitable for embedding into MIR. + transcribe_counters(&node_counters, bcb_needs_counter) } -impl BcbCounter { - fn as_term(&self) -> CovTerm { - match *self { - BcbCounter::Counter { id, .. } => CovTerm::Counter(id), - BcbCounter::Expression { id, .. } => CovTerm::Expression(id), - } - } +/// Arranges the nodes in `balanced_graph` into a list, such that earlier nodes +/// take priority in being given a counter expression instead of a physical counter. +fn make_node_counter_priority_list( + graph: &CoverageGraph, + balanced_graph: BalancedFlowGraph<&CoverageGraph>, +) -> Vec<BasicCoverageBlock> { + // A "reloop" node has exactly one out-edge, which jumps back to the top + // of an enclosing loop. Reloop nodes are typically visited more times + // than loop-exit nodes, so try to avoid giving them physical counters. + let is_reloop_node = IndexVec::from_fn_n( + |node| match graph.successors[node].as_slice() { + &[succ] => graph.dominates(succ, node), + _ => false, + }, + graph.num_nodes(), + ); + + let mut nodes = balanced_graph.iter_nodes().rev().collect::<Vec<_>>(); + // The first node is the sink, which must not get a physical counter. + assert_eq!(nodes[0], balanced_graph.sink); + // Sort the real nodes, such that earlier (lesser) nodes take priority + // in being given a counter expression instead of a physical counter. + nodes[1..].sort_by(|&a, &b| { + // Start with a dummy `Equal` to make the actual tests line up nicely. + Ordering::Equal + // Prefer a physical counter for return/yield nodes. + .then_with(|| Ord::cmp(&graph[a].is_out_summable, &graph[b].is_out_summable)) + // Prefer an expression for reloop nodes (see definition above). + .then_with(|| Ord::cmp(&is_reloop_node[a], &is_reloop_node[b]).reverse()) + // Otherwise, prefer a physical counter for dominating nodes. + .then_with(|| graph.cmp_in_dominator_order(a, b).reverse()) + }); + nodes } -impl Debug for BcbCounter { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::Counter { id, .. } => write!(fmt, "Counter({:?})", id.index()), - Self::Expression { id } => write!(fmt, "Expression({:?})", id.index()), +// Converts node counters into a form suitable for embedding into MIR. +fn transcribe_counters( + old: &NodeCounters<BasicCoverageBlock>, + bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>, +) -> CoverageCounters { + let mut new = CoverageCounters::with_num_bcbs(bcb_needs_counter.domain_size()); + + for bcb in bcb_needs_counter.iter() { + // Our counter-creation algorithm doesn't guarantee that a counter + // expression starts or ends with a positive term, so partition the + // counters into "positive" and "negative" lists for easier handling. + let (mut pos, mut neg): (Vec<_>, Vec<_>) = + old.counter_expr(bcb).iter().partition_map(|&CounterTerm { node, op }| match op { + Op::Add => Either::Left(node), + Op::Subtract => Either::Right(node), + }); + + if pos.is_empty() { + // If we somehow end up with no positive terms, fall back to + // creating a physical counter. There's no known way for this + // to happen, but we can avoid an ICE if it does. + debug_assert!(false, "{bcb:?} has no positive counter terms"); + pos = vec![bcb]; + neg = vec![]; } - } -} -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -struct BcbExpression { - lhs: BcbCounter, - op: Op, - rhs: BcbCounter, -} + // These intermediate sorts are not strictly necessary, but were helpful + // in reducing churn when switching to the current counter-creation scheme. + // They also help to slightly decrease the overall size of the expression + // table, due to more subexpressions being shared. + pos.sort(); + neg.sort(); + + let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| { + sites.into_iter().map(|node| new.ensure_phys_counter(node)).collect::<Vec<_>>() + }; + let mut pos = new_counters_for_sites(pos); + let mut neg = new_counters_for_sites(neg); + + // These sorts are also not strictly necessary; see above. + pos.sort(); + neg.sort(); + + let pos_counter = new.make_sum(&pos).expect("`pos` should not be empty"); + let new_counter = new.make_subtracted_sum(pos_counter, &neg); + new.set_node_counter(bcb, new_counter); + } -/// Enum representing either a node or an edge in the coverage graph. -/// -/// FIXME(#135481): This enum is no longer needed now that we only instrument -/// nodes and not edges. It can be removed in a subsequent PR. -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(super) enum Site { - Node { bcb: BasicCoverageBlock }, + new } /// Generates and stores coverage counter and coverage expression information -/// associated with nodes/edges in the BCB graph. +/// associated with nodes in the coverage graph. pub(super) struct CoverageCounters { /// List of places where a counter-increment statement should be injected /// into MIR, each with its corresponding counter ID. - counter_increment_sites: IndexVec<CounterId, Site>, + phys_counter_for_node: FxIndexMap<BasicCoverageBlock, CounterId>, + next_counter_id: CounterId, /// Coverage counters/expressions that are associated with individual BCBs. - node_counters: IndexVec<BasicCoverageBlock, Option<BcbCounter>>, + node_counters: IndexVec<BasicCoverageBlock, Option<CovTerm>>, /// Table of expression data, associating each expression ID with its /// corresponding operator (+ or -) and its LHS/RHS operands. - expressions: IndexVec<ExpressionId, BcbExpression>, + expressions: IndexVec<ExpressionId, Expression>, /// Remember expressions that have already been created (or simplified), /// so that we don't create unnecessary duplicates. - expressions_memo: FxHashMap<BcbExpression, BcbCounter>, + expressions_memo: FxHashMap<Expression, CovTerm>, } impl CoverageCounters { - /// Ensures that each BCB node needing a counter has one, by creating physical - /// counters or counter expressions for nodes and edges as required. - pub(super) fn make_bcb_counters( - graph: &CoverageGraph, - bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>, - ) -> Self { - let balanced_graph = BalancedFlowGraph::for_graph(graph, |n| !graph[n].is_out_summable); - let merged_graph = MergedNodeFlowGraph::for_balanced_graph(&balanced_graph); - - // A "reloop" node has exactly one out-edge, which jumps back to the top - // of an enclosing loop. Reloop nodes are typically visited more times - // than loop-exit nodes, so try to avoid giving them physical counters. - let is_reloop_node = IndexVec::from_fn_n( - |node| match graph.successors[node].as_slice() { - &[succ] => graph.dominates(succ, node), - _ => false, - }, - graph.num_nodes(), - ); - - let mut nodes = balanced_graph.iter_nodes().rev().collect::<Vec<_>>(); - // The first node is the sink, which must not get a physical counter. - assert_eq!(nodes[0], balanced_graph.sink); - // Sort the real nodes, such that earlier (lesser) nodes take priority - // in being given a counter expression instead of a physical counter. - nodes[1..].sort_by(|&a, &b| { - // Start with a dummy `Equal` to make the actual tests line up nicely. - Ordering::Equal - // Prefer a physical counter for return/yield nodes. - .then_with(|| Ord::cmp(&graph[a].is_out_summable, &graph[b].is_out_summable)) - // Prefer an expression for reloop nodes (see definition above). - .then_with(|| Ord::cmp(&is_reloop_node[a], &is_reloop_node[b]).reverse()) - // Otherwise, prefer a physical counter for dominating nodes. - .then_with(|| graph.cmp_in_dominator_order(a, b).reverse()) - }); - let node_counters = merged_graph.make_node_counters(&nodes); - - Transcriber::new(graph.num_nodes(), node_counters).transcribe_counters(bcb_needs_counter) - } - fn with_num_bcbs(num_bcbs: usize) -> Self { Self { - counter_increment_sites: IndexVec::new(), + phys_counter_for_node: FxIndexMap::default(), + next_counter_id: CounterId::ZERO, node_counters: IndexVec::from_elem_n(None, num_bcbs), expressions: IndexVec::new(), expressions_memo: FxHashMap::default(), } } - /// Creates a new physical counter for a BCB node or edge. - fn make_phys_counter(&mut self, site: Site) -> BcbCounter { - let id = self.counter_increment_sites.push(site); - BcbCounter::Counter { id } + /// Returns the physical counter for the given node, creating it if necessary. + fn ensure_phys_counter(&mut self, bcb: BasicCoverageBlock) -> CovTerm { + let id = *self.phys_counter_for_node.entry(bcb).or_insert_with(|| { + let id = self.next_counter_id; + self.next_counter_id = id + 1; + id + }); + CovTerm::Counter(id) } - fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter { - let new_expr = BcbExpression { lhs, op, rhs }; - *self.expressions_memo.entry(new_expr).or_insert_with(|| { + fn make_expression(&mut self, lhs: CovTerm, op: Op, rhs: CovTerm) -> CovTerm { + let new_expr = Expression { lhs, op, rhs }; + *self.expressions_memo.entry(new_expr.clone()).or_insert_with(|| { let id = self.expressions.push(new_expr); - BcbCounter::Expression { id } + CovTerm::Expression(id) }) } /// Creates a counter that is the sum of the given counters. /// /// Returns `None` if the given list of counters was empty. - fn make_sum(&mut self, counters: &[BcbCounter]) -> Option<BcbCounter> { + fn make_sum(&mut self, counters: &[CovTerm]) -> Option<CovTerm> { counters .iter() .copied() @@ -155,16 +183,18 @@ impl CoverageCounters { } /// Creates a counter whose value is `lhs - SUM(rhs)`. - fn make_subtracted_sum(&mut self, lhs: BcbCounter, rhs: &[BcbCounter]) -> BcbCounter { + fn make_subtracted_sum(&mut self, lhs: CovTerm, rhs: &[CovTerm]) -> CovTerm { let Some(rhs_sum) = self.make_sum(rhs) else { return lhs }; self.make_expression(lhs, Op::Subtract, rhs_sum) } pub(super) fn num_counters(&self) -> usize { - self.counter_increment_sites.len() + let num_counters = self.phys_counter_for_node.len(); + assert_eq!(num_counters, self.next_counter_id.as_usize()); + num_counters } - fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: BcbCounter) -> BcbCounter { + fn set_node_counter(&mut self, bcb: BasicCoverageBlock, counter: CovTerm) -> CovTerm { let existing = self.node_counters[bcb].replace(counter); assert!( existing.is_none(), @@ -174,16 +204,16 @@ impl CoverageCounters { } pub(super) fn term_for_bcb(&self, bcb: BasicCoverageBlock) -> Option<CovTerm> { - self.node_counters[bcb].map(|counter| counter.as_term()) + self.node_counters[bcb] } - /// Returns an iterator over all the nodes/edges in the coverage graph that + /// Returns an iterator over all the nodes in the coverage graph that /// should have a counter-increment statement injected into MIR, along with /// each site's corresponding counter ID. pub(super) fn counter_increment_sites( &self, - ) -> impl Iterator<Item = (CounterId, Site)> + Captures<'_> { - self.counter_increment_sites.iter_enumerated().map(|(id, &site)| (id, site)) + ) -> impl Iterator<Item = (CounterId, BasicCoverageBlock)> + Captures<'_> { + self.phys_counter_for_node.iter().map(|(&site, &id)| (id, site)) } /// Returns an iterator over the subset of BCB nodes that have been associated @@ -193,93 +223,13 @@ impl CoverageCounters { ) -> impl Iterator<Item = (BasicCoverageBlock, ExpressionId)> + Captures<'_> { self.node_counters.iter_enumerated().filter_map(|(bcb, &counter)| match counter { // Yield the BCB along with its associated expression ID. - Some(BcbCounter::Expression { id }) => Some((bcb, id)), + Some(CovTerm::Expression(id)) => Some((bcb, id)), // This BCB is associated with a counter or nothing, so skip it. - Some(BcbCounter::Counter { .. }) | None => None, + Some(CovTerm::Counter { .. } | CovTerm::Zero) | None => None, }) } pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> { - let old_len = self.expressions.len(); - let expressions = self - .expressions - .into_iter() - .map(|BcbExpression { lhs, op, rhs }| Expression { - lhs: lhs.as_term(), - op, - rhs: rhs.as_term(), - }) - .collect::<IndexVec<ExpressionId, _>>(); - - // Expression IDs are indexes into this vector, so make sure we didn't - // accidentally invalidate them by changing its length. - assert_eq!(old_len, expressions.len()); - expressions - } -} - -struct Transcriber { - old: NodeCounters<BasicCoverageBlock>, - new: CoverageCounters, - phys_counter_for_site: FxHashMap<Site, BcbCounter>, -} - -impl Transcriber { - fn new(num_nodes: usize, old: NodeCounters<BasicCoverageBlock>) -> Self { - Self { - old, - new: CoverageCounters::with_num_bcbs(num_nodes), - phys_counter_for_site: FxHashMap::default(), - } - } - - fn transcribe_counters( - mut self, - bcb_needs_counter: &DenseBitSet<BasicCoverageBlock>, - ) -> CoverageCounters { - for bcb in bcb_needs_counter.iter() { - let site = Site::Node { bcb }; - let (mut pos, mut neg): (Vec<_>, Vec<_>) = - self.old.counter_expr(bcb).iter().partition_map( - |&CounterTerm { node, op }| match op { - Op::Add => Either::Left(node), - Op::Subtract => Either::Right(node), - }, - ); - - if pos.is_empty() { - // If we somehow end up with no positive terms, fall back to - // creating a physical counter. There's no known way for this - // to happen, but we can avoid an ICE if it does. - debug_assert!(false, "{site:?} has no positive counter terms"); - pos = vec![bcb]; - neg = vec![]; - } - - pos.sort(); - neg.sort(); - - let mut new_counters_for_sites = |sites: Vec<BasicCoverageBlock>| { - sites - .into_iter() - .map(|node| self.ensure_phys_counter(Site::Node { bcb: node })) - .collect::<Vec<_>>() - }; - let mut pos = new_counters_for_sites(pos); - let mut neg = new_counters_for_sites(neg); - - pos.sort(); - neg.sort(); - - let pos_counter = self.new.make_sum(&pos).expect("`pos` should not be empty"); - let new_counter = self.new.make_subtracted_sum(pos_counter, &neg); - self.new.set_node_counter(bcb, new_counter); - } - - self.new - } - - fn ensure_phys_counter(&mut self, site: Site) -> BcbCounter { - *self.phys_counter_for_site.entry(site).or_insert_with(|| self.new.make_phys_counter(site)) + self.expressions } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 25dc7f31227..392b54c8d81 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -135,7 +135,7 @@ impl CoverageGraph { bb_to_bcb[bb] = Some(bcb); } - let is_out_summable = basic_blocks.last().map_or(false, |&bb| { + let is_out_summable = basic_blocks.last().is_some_and(|&bb| { bcb_filtered_successors(mir_body[bb].terminator()).is_out_summable() }); let bcb_data = BasicCoverageBlockData { basic_blocks, is_out_summable }; diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index b1b609595b7..19568735df7 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -21,7 +21,7 @@ use rustc_span::Span; use rustc_span::def_id::LocalDefId; use tracing::{debug, debug_span, trace}; -use crate::coverage::counters::{CoverageCounters, Site}; +use crate::coverage::counters::CoverageCounters; use crate::coverage::graph::CoverageGraph; use crate::coverage::mappings::ExtractedMappings; @@ -89,8 +89,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: return; } - let coverage_counters = - CoverageCounters::make_bcb_counters(&graph, &bcbs_with_counter_mappings); + let coverage_counters = counters::make_bcb_counters(&graph, &bcbs_with_counter_mappings); let mappings = create_mappings(&extracted_mappings, &coverage_counters); if mappings.is_empty() { @@ -239,14 +238,8 @@ fn inject_coverage_statements<'tcx>( coverage_counters: &CoverageCounters, ) { // Inject counter-increment statements into MIR. - for (id, site) in coverage_counters.counter_increment_sites() { - // Determine the block to inject a counter-increment statement into. - // For BCB nodes this is just their first block, but for edges we need - // to create a new block between the two BCBs, and inject into that. - let target_bb = match site { - Site::Node { bcb } => graph[bcb].leader_bb(), - }; - + for (id, bcb) in coverage_counters.counter_increment_sites() { + let target_bb = graph[bcb].leader_bb(); inject_statement(mir_body, CoverageKind::CounterIncrement { id }, target_bb); } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index cc44114782c..51af77778af 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -408,6 +408,18 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { state: &mut State<FlatSet<Scalar>>, ) -> ValueOrPlace<FlatSet<Scalar>> { let val = match rvalue { + Rvalue::Len(place) => { + let place_ty = place.ty(self.local_decls, self.tcx); + if let ty::Array(_, len) = place_ty.ty.kind() { + Const::Ty(self.tcx.types.usize, *len) + .try_eval_scalar(self.tcx, self.typing_env) + .map_or(FlatSet::Top, FlatSet::Elem) + } else if let [ProjectionElem::Deref] = place.projection[..] { + state.get_len(place.local.into(), &self.map) + } else { + FlatSet::Top + } + } Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => { let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else { return ValueOrPlace::Value(FlatSet::Top); diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 1ac4d835946..b4f9f1f08ef 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -575,6 +575,7 @@ impl WriteInfo { | Rvalue::NullaryOp(_, _) | Rvalue::Ref(_, _, _) | Rvalue::RawPtr(_, _) + | Rvalue::Len(_) | Rvalue::Discriminant(_) | Rvalue::CopyForDeref(_) => {} } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 015633d145f..a2fd46043ca 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -10,6 +10,28 @@ use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; #[derive(LintDiagnostic)] +#[diag(mir_transform_unconditional_recursion)] +#[help] +pub(crate) struct UnconditionalRecursion { + #[label] + pub(crate) span: Span, + #[label(mir_transform_unconditional_recursion_call_site_label)] + pub(crate) call_sites: Vec<Span>, +} + +#[derive(Diagnostic)] +#[diag(mir_transform_force_inline_attr)] +#[note] +pub(crate) struct InvalidForceInline { + #[primary_span] + pub attr_span: Span, + #[label(mir_transform_callee)] + pub callee_span: Span, + pub callee: String, + pub reason: &'static str, +} + +#[derive(LintDiagnostic)] pub(crate) enum ConstMutate { #[diag(mir_transform_const_modify)] #[note] diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index affc4cf0afc..cb03b422d9e 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -223,6 +223,8 @@ enum Value<'tcx> { Projection(VnIndex, ProjectionElem<VnIndex, Ty<'tcx>>), /// Discriminant of the given value. Discriminant(VnIndex), + /// Length of an array or slice. + Len(VnIndex), // Operations. NullaryOp(NullOp<'tcx>, Ty<'tcx>), @@ -511,6 +513,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?; discr_value.into() } + Len(slice) => { + 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).discard_err()?; + let imm = ImmTy::from_uint(len, usize_layout); + imm.into() + } NullaryOp(null_op, ty) => { let layout = self.ecx.layout_of(ty).ok()?; if let NullOp::SizeOf | NullOp::AlignOf = null_op @@ -854,6 +863,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Operations. + Rvalue::Len(ref mut place) => return self.simplify_len(place, location), Rvalue::Cast(ref mut kind, ref mut value, to) => { return self.simplify_cast(kind, value, to, location); } @@ -1474,6 +1484,47 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(self.insert(Value::Cast { kind: *kind, value, from, to })) } + fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> { + // 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.types.usize, + self.tcx, + )); + } + + let mut inner = self.simplify_place_value(place, location)?; + + // The length information is stored in the wide pointer. + // Reborrowing copies length information from one pointer to the other. + while let Value::Address { place: borrowed, .. } = self.get(inner) + && let [PlaceElem::Deref] = borrowed.projection[..] + && let Some(borrowed) = self.locals[borrowed.local] + { + inner = borrowed; + } + + // We have an unsizing cast, which assigns the length to wide pointer metadata. + if let Value::Cast { kind, from, to, .. } = self.get(inner) + && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind + && let Some(from) = from.builtin_deref(true) + && let ty::Array(_, len) = from.kind() + && let Some(to) = to.builtin_deref(true) + && let ty::Slice(..) = to.kind() + { + return self.insert_constant(Const::from_ty_const( + *len, + self.tcx.types.usize, + self.tcx, + )); + } + + // Fallback: a symbolic `Len`. + Some(self.insert(Value::Len(inner))) + } + fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool { let left_meta_ty = left_ptr_ty.pointee_metadata_ty_or_projection(self.tcx); let right_meta_ty = right_ptr_ty.pointee_metadata_ty_or_projection(self.tcx); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 470393c9ae1..2052e28325c 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -21,8 +21,8 @@ use tracing::{debug, instrument, trace, trace_span}; use crate::cost_checker::CostChecker; use crate::deref_separator::deref_finder; use crate::simplify::simplify_cfg; -use crate::util; use crate::validate::validate_types; +use crate::{check_inline, util}; pub(crate) mod cycle; @@ -575,7 +575,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( check_mir_is_available(inliner, caller_body, callsite.callee)?; let callee_attrs = tcx.codegen_fn_attrs(callsite.callee.def_id()); - rustc_mir_build::check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?; + check_inline::is_inline_valid_on_fn(tcx, callsite.callee.def_id())?; check_codegen_attributes(inliner, callsite, callee_attrs)?; let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); @@ -590,7 +590,7 @@ fn try_inlining<'tcx, I: Inliner<'tcx>>( } let callee_body = try_instance_mir(tcx, callsite.callee.def)?; - rustc_mir_build::check_inline::is_inline_valid_on_body(tcx, callee_body)?; + check_inline::is_inline_valid_on_body(tcx, callee_body)?; inliner.check_callee_mir_body(callsite, callee_body, callee_attrs)?; let Ok(callee_body) = callsite.callee.try_instantiate_mir_and_normalize_erasing_regions( diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 20e2e3e8ba2..5a36519e6a3 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -46,6 +46,7 @@ impl<'tcx> crate::MirPass<'tcx> for InstSimplify { } ctx.simplify_bool_cmp(rvalue); ctx.simplify_ref_deref(rvalue); + ctx.simplify_len(rvalue); ctx.simplify_ptr_aggregate(rvalue); ctx.simplify_cast(rvalue); ctx.simplify_repeated_aggregate(rvalue); @@ -161,6 +162,18 @@ impl<'tcx> InstSimplifyContext<'_, 'tcx> { } } + /// Transform `Len([_; N])` ==> `N`. + fn simplify_len(&self, rvalue: &mut Rvalue<'tcx>) { + if let Rvalue::Len(ref place) = *rvalue { + let place_ty = place.ty(self.local_decls, self.tcx).ty; + if let ty::Array(_, len) = *place_ty.kind() { + let const_ = Const::from_ty_const(len, self.tcx.types.usize, self.tcx); + let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None }; + *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); + } + } + } + /// Transform `Aggregate(RawPtr, [p, ()])` ==> `Cast(PtrToPtr, p)`. fn simplify_ptr_aggregate(&self, rvalue: &mut Rvalue<'tcx>) { if let Rvalue::Aggregate(box AggregateKind::RawPtr(pointee_ty, mutability), fields) = rvalue diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 9b3a0e67295..f4ac5c6aa80 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -440,6 +440,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | Rvalue::Use(..) | Rvalue::CopyForDeref(..) | Rvalue::Repeat(..) + | Rvalue::Len(..) | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) | Rvalue::Discriminant(..) @@ -599,6 +600,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } + Len(place) => { + let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind() + { + n.try_to_target_usize(self.tcx)? + } else { + match self.get_const(place)? { + Value::Immediate(src) => src.len(&self.ecx).discard_err()?, + Value::Aggregate { fields, .. } => fields.len() as u64, + Value::Uninit => return None, + } + }; + ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into() + } + Ref(..) | RawPtr(..) => return None, NullaryOp(ref null_op, ty) => { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index db999bea986..d1bacf1f598 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -114,6 +114,8 @@ declare_passes! { mod add_moves_for_packed_drops : AddMovesForPackedDrops; mod add_retag : AddRetag; mod add_subtyping_projections : Subtyper; + mod check_inline : CheckForceInline; + mod check_call_recursion : CheckCallRecursion, CheckDropRecursion; mod check_alignment : CheckAlignment; mod check_const_item_mutation : CheckConstItemMutation; mod check_packed_ref : CheckPackedRef; @@ -375,6 +377,8 @@ fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> { &mut body, &[ // MIR-level lints. + &Lint(check_inline::CheckForceInline), + &Lint(check_call_recursion::CheckCallRecursion), &Lint(check_packed_ref::CheckPackedRef), &Lint(check_const_item_mutation::CheckConstItemMutation), &Lint(function_item_references::FunctionItemReferences), @@ -505,10 +509,6 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & run_analysis_to_runtime_passes(tcx, &mut body); - // Now that drop elaboration has been performed, we can check for - // unconditional drop recursion. - rustc_mir_build::lints::check_drop_recursion(tcx, &body); - tcx.alloc_steal_mir(body) } @@ -570,6 +570,8 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Calling this after `PostAnalysisNormalize` ensures that we don't deal with opaque types. &add_subtyping_projections::Subtyper, &elaborate_drops::ElaborateDrops, + // Needs to happen after drop elaboration. + &Lint(check_call_recursion::CheckDropRecursion), // This will remove extraneous landing pads which are no longer // necessary as well as forcing any call in a non-unwinding // function calling a possibly-unwinding function to abort the process. diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 7451f419304..6be95b1f0f1 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -430,7 +430,9 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(op)? } - Rvalue::Discriminant(place) => self.validate_place(place.as_ref())?, + Rvalue::Discriminant(place) | Rvalue::Len(place) => { + self.validate_place(place.as_ref())? + } Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 414477d9004..b62e34ac08d 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1018,6 +1018,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } Rvalue::Ref(..) => {} + Rvalue::Len(p) => { + let pty = p.ty(&self.body.local_decls, self.tcx).ty; + check_kinds!( + pty, + "Cannot compute length of non-array type {:?}", + ty::Array(..) | ty::Slice(..) + ); + } Rvalue::BinaryOp(op, vals) => { use BinOp::*; let a = vals.0.ty(&self.body.local_decls, self.tcx); @@ -1116,6 +1124,14 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ); } UnOp::PtrMetadata => { + if !matches!(self.body.phase, MirPhase::Runtime(_)) { + // It would probably be fine to support this in earlier phases, but at + // the time of writing it's only ever introduced from intrinsic + // lowering or other runtime-phase optimization passes, so earlier + // things can just `bug!` on it. + self.fail(location, "PtrMetadata should be in runtime MIR only"); + } + check_kinds!( a, "Cannot PtrMetadata non-pointer non-reference type {:?}", diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml index f9168112216..451c215566b 100644 --- a/compiler/rustc_next_trait_solver/Cargo.toml +++ b/compiler/rustc_next_trait_solver/Cargo.toml @@ -13,7 +13,6 @@ rustc_macros = { path = "../rustc_macros", optional = true } rustc_serialize = { path = "../rustc_serialize", optional = true } rustc_type_ir = { path = "../rustc_type_ir", default-features = false } rustc_type_ir_macros = { path = "../rustc_type_ir_macros" } -smallvec = "1.8.1" tracing = "0.1" # tidy-alphabetical-end diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs index 8a54a4ece98..62a7c84bc28 100644 --- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs @@ -273,7 +273,7 @@ impl<'a, D: SolverDelegate<Interner = I>, I: Interner> Canonicalizer<'a, D, I> { // // For this we set `next_orig_uv` to the next smallest, not yet compressed, // universe of the input. - if next_orig_uv.map_or(true, |curr_next_uv| uv.cannot_name(curr_next_uv)) { + if next_orig_uv.is_none_or(|curr_next_uv| uv.cannot_name(curr_next_uv)) { next_orig_uv = Some(uv); } } diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 37678bfd880..8d1194ee539 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -277,23 +277,7 @@ where param_env: I::ParamEnv, ty: I::Ty, ) -> Result<I::Ty, NoSolution> { - if let ty::Alias(..) = ty.kind() { - let normalized_ty = self.next_ty_infer(); - let alias_relate_goal = Goal::new( - self.cx(), - param_env, - ty::PredicateKind::AliasRelate( - ty.into(), - normalized_ty.into(), - ty::AliasRelationDirection::Equate, - ), - ); - self.add_goal(GoalSource::Misc, alias_relate_goal); - self.try_evaluate_added_goals()?; - Ok(self.resolve_vars_if_possible(normalized_ty)) - } else { - Ok(ty) - } + self.structurally_normalize_term(param_env, ty.into()).map(|term| term.expect_ty()) } /// Normalize a const for when it is structurally matched on, or more likely @@ -308,22 +292,34 @@ where param_env: I::ParamEnv, ct: I::Const, ) -> Result<I::Const, NoSolution> { - if let ty::ConstKind::Unevaluated(..) = ct.kind() { - let normalized_ct = self.next_const_infer(); + self.structurally_normalize_term(param_env, ct.into()).map(|term| term.expect_const()) + } + + /// Normalize a term for when it is structurally matched on. + /// + /// This function is necessary in nearly all cases before matching on a ty/const. + /// Not doing so is likely to be incomplete and therefore unsound during coherence. + fn structurally_normalize_term( + &mut self, + param_env: I::ParamEnv, + term: I::Term, + ) -> Result<I::Term, NoSolution> { + if let Some(_) = term.to_alias_term() { + let normalized_term = self.next_term_infer_of_kind(term); let alias_relate_goal = Goal::new( self.cx(), param_env, ty::PredicateKind::AliasRelate( - ct.into(), - normalized_ct.into(), + term, + normalized_term, ty::AliasRelationDirection::Equate, ), ); self.add_goal(GoalSource::Misc, alias_relate_goal); self.try_evaluate_added_goals()?; - Ok(self.resolve_vars_if_possible(normalized_ct)) + Ok(self.resolve_vars_if_possible(normalized_term)) } else { - Ok(ct) + Ok(term) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 4faa243c02a..513fc9355c8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -8,7 +8,6 @@ use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::solve::CanonicalResponse; use rustc_type_ir::visit::TypeVisitableExt as _; use rustc_type_ir::{self as ty, Interner, TraitPredicate, TypingMode, Upcast as _, elaborate}; -use smallvec::SmallVec; use tracing::{instrument, trace}; use crate::delegate::SolverDelegate; @@ -1199,33 +1198,42 @@ where // nested requirements, over all others. This is a fix for #53123 and // prevents where-bounds from accidentally extending the lifetime of a // variable. - if candidates - .iter() - .any(|c| matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial))) - { - let trivial_builtin_impls: SmallVec<[_; 1]> = candidates - .iter() - .filter(|c| { - matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial)) - }) - .map(|c| c.result) - .collect(); + let mut trivial_builtin_impls = candidates.iter().filter(|c| { + matches!(c.source, CandidateSource::BuiltinImpl(BuiltinImplSource::Trivial)) + }); + if let Some(candidate) = trivial_builtin_impls.next() { // There should only ever be a single trivial builtin candidate // as they would otherwise overlap. - assert_eq!(trivial_builtin_impls.len(), 1); - return if let Some(response) = self.try_merge_responses(&trivial_builtin_impls) { - Ok((response, Some(TraitGoalProvenVia::Misc))) - } else { - Ok((self.bail_with_ambiguity(&trivial_builtin_impls), None)) - }; + assert!(trivial_builtin_impls.next().is_none()); + return Ok((candidate.result, Some(TraitGoalProvenVia::Misc))); } // If there are non-global where-bounds, prefer where-bounds // (including global ones) over everything else. let has_non_global_where_bounds = candidates.iter().any(|c| match c.source { CandidateSource::ParamEnv(idx) => { - let where_bound = goal.param_env.caller_bounds().get(idx); - where_bound.has_bound_vars() || !where_bound.is_global() + let where_bound = goal.param_env.caller_bounds().get(idx).unwrap(); + let ty::ClauseKind::Trait(trait_pred) = where_bound.kind().skip_binder() else { + unreachable!("expected trait-bound: {where_bound:?}"); + }; + + if trait_pred.has_bound_vars() || !trait_pred.is_global() { + return true; + } + + // We don't consider a trait-bound global if it has a projection bound. + // + // See ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs + // for an example where this is necessary. + for p in goal.param_env.caller_bounds().iter() { + if let ty::ClauseKind::Projection(proj) = p.kind().skip_binder() { + if proj.projection_term.trait_ref(self.cx()) == trait_pred.trait_ref { + return true; + } + } + } + + false } _ => false, }); diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index f963a424a7f..e681987ff07 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -11,18 +11,21 @@ #![feature(if_let_guard)] #![feature(iter_intersperse)] #![feature(let_chains)] +#![feature(string_from_utf8_lossy_owned)] #![warn(unreachable_pub)] // tidy-alphabetical-end -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::str::Utf8Error; use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; use rustc_ast::{AttrItem, Attribute, MetaItemInner, token}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Diag, FatalError, PResult}; +use rustc_errors::{Diag, EmissionGuarantee, FatalError, PResult, pluralize}; use rustc_session::parse::ParseSess; +use rustc_span::source_map::SourceMap; use rustc_span::{FileName, SourceFile, Span}; pub use unicode_normalization::UNICODE_VERSION as UNICODE_NORMALIZATION_VERSION; @@ -73,9 +76,22 @@ pub fn new_parser_from_file<'a>( 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 sm = psess.source_map(); + let source_file = sm.load_file(path).unwrap_or_else(|e| { + let msg = format!("couldn't read `{}`: {}", path.display(), e); let mut err = psess.dcx().struct_fatal(msg); + if let Ok(contents) = std::fs::read(path) + && let Err(utf8err) = String::from_utf8(contents.clone()) + { + utf8_error( + sm, + &path.display().to_string(), + sp, + &mut err, + utf8err.utf8_error(), + &contents, + ); + } if let Some(sp) = sp { err.span(sp); } @@ -84,6 +100,49 @@ pub fn new_parser_from_file<'a>( new_parser_from_source_file(psess, source_file) } +pub fn utf8_error<E: EmissionGuarantee>( + sm: &SourceMap, + path: &str, + sp: Option<Span>, + err: &mut Diag<'_, E>, + utf8err: Utf8Error, + contents: &[u8], +) { + // The file exists, but it wasn't valid UTF-8. + let start = utf8err.valid_up_to(); + let note = format!("invalid utf-8 at byte `{start}`"); + let msg = if let Some(len) = utf8err.error_len() { + format!( + "byte{s} `{bytes}` {are} not valid utf-8", + bytes = if len == 1 { + format!("{:?}", contents[start]) + } else { + format!("{:?}", &contents[start..start + len]) + }, + s = pluralize!(len), + are = if len == 1 { "is" } else { "are" }, + ) + } else { + note.clone() + }; + let contents = String::from_utf8_lossy(contents).to_string(); + let source = sm.new_source_file(PathBuf::from(path).into(), contents); + let span = Span::with_root_ctxt( + source.normalized_byte_pos(start as u32), + source.normalized_byte_pos(start as u32), + ); + if span.is_dummy() { + err.note(note); + } else { + if sp.is_some() { + err.span_note(span, msg); + } else { + err.span(span); + err.span_label(span, msg); + } + } +} + /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing /// the initial token stream. fn new_parser_from_source_file( diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 7533e75ffe2..5cd02128287 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2095,7 +2095,7 @@ impl<'a> Parser<'a> { // point literal here, since there's no use of the exponent // syntax that also constitutes a valid integer, so we need // not check for that. - if suffix.map_or(true, |s| s == sym::f32 || s == sym::f64) + if suffix.is_none_or(|s| s == sym::f32 || s == sym::f64) && symbol.as_str().chars().all(|c| c.is_numeric() || c == '_') && self.token.span.hi() == next_token.span.lo() { diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 8b6b37c0f8f..86f673c100c 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -11,7 +11,7 @@ use rustc_session::errors::report_lit_error; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNSAFE_ATTR_OUTSIDE_UNSAFE}; use rustc_session::parse::ParseSess; -use rustc_span::{BytePos, Span, Symbol, sym}; +use rustc_span::{Span, Symbol, sym}; use crate::{errors, parse_in}; @@ -164,11 +164,7 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: // wrapping it in `unsafe(...)`. Otherwise, we suggest putting the // `unsafe(`, `)` right after and right before the opening and closing // square bracket respectively. - let diag_span = if attr_item.span().can_be_used_for_suggestions() { - attr_item.span() - } else { - attr.span.with_lo(attr.span.lo() + BytePos(2)).with_hi(attr.span.hi() - BytePos(1)) - }; + let diag_span = attr_item.span(); if attr.span.at_least_rust_2024() { psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 9eb335cb34c..5418f054beb 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -514,13 +514,7 @@ impl<'a> Parser<'a> { /// Consumes all whitespace characters until the first non-whitespace character fn ws(&mut self) { - while let Some(&(_, c)) = self.cur.peek() { - if c.is_whitespace() { - self.cur.next(); - } else { - break; - } - } + while let Some(_) = self.cur.next_if(|&(_, c)| c.is_whitespace()) {} } /// Parses all of a string which is to be considered a "raw literal" in a @@ -545,7 +539,7 @@ impl<'a> Parser<'a> { } } } - &self.input[start..self.input.len()] + &self.input[start..] } /// Parses an `Argument` structure, or what's contained within braces inside the format string. diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl index 3ed600a717f..133d84572e6 100644 --- a/compiler/rustc_passes/messages.ftl +++ b/compiler/rustc_passes/messages.ftl @@ -502,11 +502,6 @@ passes_multiple_rustc_main = .first = first `#[rustc_main]` function .additional = additional `#[rustc_main]` function -passes_multiple_start_functions = - multiple `start` functions - .label = multiple `start` functions - .previous = previous `#[start]` function here - passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, union, or trait .label = is not a struct, enum, union, or trait diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 1b2b8ac5dd9..dbb87443eed 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -275,7 +275,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | sym::lang | sym::needs_allocator | sym::default_lib_allocator - | sym::start | sym::custom_mir, .. ] => {} @@ -2655,7 +2654,6 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { sym::repr, sym::path, sym::automatically_derived, - sym::start, sym::rustc_main, sym::derive, sym::test, diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index c5dc8e68fe8..34deb854e0f 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -1231,7 +1231,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { continue; } - let is_positional = variant.fields.raw.first().map_or(false, |field| { + let is_positional = variant.fields.raw.first().is_some_and(|field| { field.name.as_str().starts_with(|c: char| c.is_ascii_digit()) }); let report_on = diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index 4949a4316a7..22291c9282d 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -10,9 +10,7 @@ use rustc_session::RemapFileNameExt; use rustc_session::config::{CrateType, EntryFnType, RemapPathScopeComponents, sigpipe}; use rustc_span::{Span, Symbol, sym}; -use crate::errors::{ - AttrOnlyInFunctions, ExternMain, MultipleRustcMain, MultipleStartFunctions, NoMainErr, -}; +use crate::errors::{AttrOnlyInFunctions, ExternMain, MultipleRustcMain, NoMainErr}; struct EntryContext<'tcx> { tcx: TyCtxt<'tcx>, @@ -20,9 +18,6 @@ struct EntryContext<'tcx> { /// The function has the `#[rustc_main]` attribute. rustc_main_fn: Option<(LocalDefId, Span)>, - /// The function that has the attribute `#[start]` on it. - start_fn: Option<(LocalDefId, Span)>, - /// The functions that one might think are `main` but aren't, e.g. /// main functions not defined at the top level. For diagnostics. non_main_fns: Vec<Span>, @@ -40,8 +35,7 @@ fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { return None; } - let mut ctxt = - EntryContext { tcx, rustc_main_fn: None, start_fn: None, non_main_fns: Vec::new() }; + let mut ctxt = EntryContext { tcx, rustc_main_fn: None, non_main_fns: Vec::new() }; for id in tcx.hir().items() { check_and_search_item(id, &mut ctxt); @@ -57,7 +51,7 @@ fn attr_span_by_symbol(ctxt: &EntryContext<'_>, id: ItemId, sym: Symbol) -> Opti fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) { - for attr in [sym::start, sym::rustc_main] { + for attr in [sym::rustc_main] { if let Some(span) = attr_span_by_symbol(ctxt, id, attr) { ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr }); } @@ -91,24 +85,11 @@ fn check_and_search_item(id: ItemId, ctxt: &mut EntryContext<'_>) { }); } } - EntryPointType::Start => { - if ctxt.start_fn.is_none() { - ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id))); - } else { - ctxt.tcx.dcx().emit_err(MultipleStartFunctions { - span: ctxt.tcx.def_span(id.owner_id), - labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()), - previous: ctxt.start_fn.unwrap().1, - }); - } - } } } fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId, EntryFnType)> { - if let Some((def_id, _)) = visitor.start_fn { - Some((def_id.to_def_id(), EntryFnType::Start)) - } else if let Some((local_def_id, _)) = visitor.rustc_main_fn { + if let Some((local_def_id, _)) = visitor.rustc_main_fn { let def_id = local_def_id.to_def_id(); Some((def_id, EntryFnType::Main { sigpipe: sigpipe(tcx) })) } else { diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index c3043ac60aa..3d38b00e99f 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1314,17 +1314,6 @@ pub(crate) struct MultipleRustcMain { } #[derive(Diagnostic)] -#[diag(passes_multiple_start_functions, code = E0138)] -pub(crate) struct MultipleStartFunctions { - #[primary_span] - pub span: Span, - #[label] - pub labeled: Span, - #[label(passes_previous)] - pub previous: Span, -} - -#[derive(Diagnostic)] #[diag(passes_extern_main)] pub(crate) struct ExternMain { #[primary_span] diff --git a/compiler/rustc_privacy/messages.ftl b/compiler/rustc_privacy/messages.ftl index 7785f1a7f81..43c34a109d7 100644 --- a/compiler/rustc_privacy/messages.ftl +++ b/compiler/rustc_privacy/messages.ftl @@ -1,5 +1,19 @@ -privacy_field_is_private = field `{$field_name}` of {$variant_descr} `{$def_path_str}` is private -privacy_field_is_private_is_update_syntax_label = field `{$field_name}` is private +privacy_field_is_private = + {$len -> + [1] field + *[other] fields + } {$field_names} of {$variant_descr} `{$def_path_str}` {$len -> + [1] is + *[other] are + } private + .label = in this type +privacy_field_is_private_is_update_syntax_label = {$rest_len -> + [1] field + *[other] fields + } {$rest_field_names} {$rest_len -> + [1] is + *[other] are + } private privacy_field_is_private_label = private field privacy_from_private_dep_in_public_interface = diff --git a/compiler/rustc_privacy/src/errors.rs b/compiler/rustc_privacy/src/errors.rs index f5e641eb642..4d1d58c0852 100644 --- a/compiler/rustc_privacy/src/errors.rs +++ b/compiler/rustc_privacy/src/errors.rs @@ -1,5 +1,5 @@ -use rustc_errors::DiagArgFromDisplay; use rustc_errors::codes::*; +use rustc_errors::{DiagArgFromDisplay, MultiSpan}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -7,12 +7,15 @@ use rustc_span::{Span, Symbol}; #[diag(privacy_field_is_private, code = E0451)] pub(crate) struct FieldIsPrivate { #[primary_span] - pub span: Span, - pub field_name: Symbol, + pub span: MultiSpan, + #[label] + pub struct_span: Option<Span>, + pub field_names: String, pub variant_descr: &'static str, pub def_path_str: String, #[subdiagnostic] - pub label: FieldIsPrivateLabel, + pub labels: Vec<FieldIsPrivateLabel>, + pub len: usize, } #[derive(Subdiagnostic)] @@ -21,7 +24,8 @@ pub(crate) enum FieldIsPrivateLabel { IsUpdateSyntax { #[primary_span] span: Span, - field_name: Symbol, + rest_field_names: String, + rest_len: usize, }, #[label(privacy_field_is_private_label)] Other { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index e484cfed06b..cb7b0815a49 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -24,6 +24,7 @@ use rustc_ast::MacroDef; use rustc_ast::visit::{VisitorResult, try_visit}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; +use rustc_errors::MultiSpan; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, Visitor}; @@ -38,7 +39,7 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_session::lint; use rustc_span::hygiene::Transparency; -use rustc_span::{Ident, Span, kw, sym}; +use rustc_span::{Ident, Span, Symbol, kw, sym}; use tracing::debug; use {rustc_attr_parsing as attr, rustc_hir as hir}; @@ -921,31 +922,95 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { &mut self, hir_id: hir::HirId, // ID of the field use use_ctxt: Span, // syntax context of the field name at the use site - span: Span, // span of the field pattern, e.g., `x: 0` def: ty::AdtDef<'tcx>, // definition of the struct or enum field: &'tcx ty::FieldDef, - in_update_syntax: bool, - ) { + ) -> bool { if def.is_enum() { - return; + return true; } // definition of the field let ident = Ident::new(kw::Empty, use_ctxt); let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1; - if !field.vis.is_accessible_from(def_id, self.tcx) { - self.tcx.dcx().emit_err(FieldIsPrivate { - span, - field_name: field.name, - variant_descr: def.variant_descr(), - def_path_str: self.tcx.def_path_str(def.did()), - label: if in_update_syntax { - FieldIsPrivateLabel::IsUpdateSyntax { span, field_name: field.name } - } else { - FieldIsPrivateLabel::Other { span } - }, - }); + !field.vis.is_accessible_from(def_id, self.tcx) + } + + // Checks that a field in a struct constructor (expression or pattern) is accessible. + fn emit_unreachable_field_error( + &mut self, + fields: Vec<(Symbol, Span, bool /* field is present */)>, + def: ty::AdtDef<'tcx>, // definition of the struct or enum + update_syntax: Option<Span>, + struct_span: Span, + ) { + if def.is_enum() || fields.is_empty() { + return; } + + // error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private + // --> $DIR/visibility.rs:18:13 + // | + // LL | let _x = Alpha { + // | ----- in this type # from `def` + // LL | beta: 0, + // | ^^^^^^^ private field # `fields.2` is `true` + // LL | .. + // | ^^ field `gamma` is private # `fields.2` is `false` + + // Get the list of all private fields for the main message. + let field_names: Vec<_> = fields.iter().map(|(name, _, _)| name).collect(); + let field_names = match &field_names[..] { + [] => return, + [name] => format!("`{name}`"), + [fields @ .., last] => format!( + "{} and `{last}`", + fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "), + ), + }; + let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::<Vec<Span>>().into(); + + // Get the list of all private fields when pointing at the `..rest`. + let rest_field_names: Vec<_> = + fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect(); + let rest_len = rest_field_names.len(); + let rest_field_names = match &rest_field_names[..] { + [] => String::new(), + [name] => format!("`{name}`"), + [fields @ .., last] => format!( + "{} and `{last}`", + fields.iter().map(|f| format!("`{f}`")).collect::<Vec<_>>().join(", "), + ), + }; + // Get all the labels for each field or `..rest` in the primary MultiSpan. + let labels = fields + .iter() + .filter(|(_, _, is_present)| *is_present) + .map(|(_, span, _)| FieldIsPrivateLabel::Other { span: *span }) + .chain(update_syntax.iter().map(|span| FieldIsPrivateLabel::IsUpdateSyntax { + span: *span, + rest_field_names: rest_field_names.clone(), + rest_len, + })) + .collect(); + + self.tcx.dcx().emit_err(FieldIsPrivate { + span, + struct_span: if self + .tcx + .sess + .source_map() + .is_multiline(fields[0].1.between(struct_span)) + { + Some(struct_span) + } else { + None + }, + field_names: field_names.clone(), + variant_descr: def.variant_descr(), + def_path_str: self.tcx.def_path_str(def.did()), + labels, + len: fields.len(), + }); } fn check_expanded_fields( @@ -955,7 +1020,9 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { fields: &[hir::ExprField<'tcx>], hir_id: hir::HirId, span: Span, + struct_span: Span, ) { + let mut failed_fields = vec![]; for (vf_index, variant_field) in variant.fields.iter_enumerated() { let field = fields.iter().find(|f| self.typeck_results().field_index(f.hir_id) == vf_index); @@ -963,8 +1030,15 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { Some(field) => (field.hir_id, field.ident.span, field.span), None => (hir_id, span, span), }; - self.check_field(hir_id, use_ctxt, span, adt, variant_field, true); + if self.check_field(hir_id, use_ctxt, adt, variant_field) { + let name = match field { + Some(field) => field.ident.name, + None => variant_field.name, + }; + failed_fields.push((name, span, field.is_some())); + } } + self.emit_unreachable_field_error(failed_fields, adt, Some(span), struct_span); } } @@ -990,24 +1064,35 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { // If the expression uses FRU we need to make sure all the unmentioned fields // are checked for privacy (RFC 736). Rather than computing the set of // unmentioned fields, just check them all. - self.check_expanded_fields(adt, variant, fields, base.hir_id, base.span); + self.check_expanded_fields( + adt, + variant, + fields, + base.hir_id, + base.span, + qpath.span(), + ); } hir::StructTailExpr::DefaultFields(span) => { - self.check_expanded_fields(adt, variant, fields, expr.hir_id, span); + self.check_expanded_fields( + adt, + variant, + fields, + expr.hir_id, + span, + qpath.span(), + ); } hir::StructTailExpr::None => { + let mut failed_fields = vec![]; for field in fields { - let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span); + let (hir_id, use_ctxt) = (field.hir_id, field.ident.span); let index = self.typeck_results().field_index(field.hir_id); - self.check_field( - hir_id, - use_ctxt, - span, - adt, - &variant.fields[index], - false, - ); + if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) { + failed_fields.push((field.ident.name, field.ident.span, true)); + } } + self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span()); } } } @@ -1020,11 +1105,15 @@ impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { let res = self.typeck_results().qpath_res(qpath, pat.hir_id); let adt = self.typeck_results().pat_ty(pat).ty_adt_def().unwrap(); let variant = adt.variant_of_res(res); + let mut failed_fields = vec![]; for field in fields { - let (hir_id, use_ctxt, span) = (field.hir_id, field.ident.span, field.span); + let (hir_id, use_ctxt) = (field.hir_id, field.ident.span); let index = self.typeck_results().field_index(field.hir_id); - self.check_field(hir_id, use_ctxt, span, adt, &variant.fields[index], false); + if self.check_field(hir_id, use_ctxt, adt, &variant.fields[index]) { + failed_fields.push((field.ident.name, field.ident.span, true)); + } } + self.emit_unreachable_field_error(failed_fields, adt, None, qpath.span()); } intravisit::walk_pat(self, pat); diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs index 3e179c61f39..a8c2aa98cd0 100644 --- a/compiler/rustc_query_system/src/query/job.rs +++ b/compiler/rustc_query_system/src/query/job.rs @@ -567,7 +567,7 @@ pub fn print_query_stack<Qcx: QueryContext>( qcx: Qcx, mut current_query: Option<QueryJobId>, dcx: DiagCtxtHandle<'_>, - num_frames: Option<usize>, + limit_frames: Option<usize>, mut file: Option<std::fs::File>, ) -> usize { // Be careful relying on global state here: this code is called from @@ -584,7 +584,7 @@ pub fn print_query_stack<Qcx: QueryContext>( let Some(query_info) = query_map.get(&query) else { break; }; - if Some(count_printed) < num_frames || num_frames.is_none() { + if Some(count_printed) < limit_frames || limit_frames.is_none() { // Only print to stderr as many stack frames as `num_frames` when present. // FIXME: needs translation #[allow(rustc::diagnostic_outside_of_impl)] @@ -615,5 +615,5 @@ pub fn print_query_stack<Qcx: QueryContext>( if let Some(ref mut file) = file { let _ = writeln!(file, "end of query stack"); } - count_printed + count_total } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3fe1eed243f..eec9e9a8515 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -645,10 +645,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let self_spans = items .iter() .filter_map(|(use_tree, _)| { - if let ast::UseTreeKind::Simple(..) = use_tree.kind { - if use_tree.ident().name == kw::SelfLower { - return Some(use_tree.span); - } + if let ast::UseTreeKind::Simple(..) = use_tree.kind + && use_tree.ident().name == kw::SelfLower + { + return Some(use_tree.span); } None @@ -947,19 +947,19 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { let imported_binding = self.r.import(binding, import); if parent == self.r.graph_root { let ident = ident.normalize_to_macros_2_0(); - if let Some(entry) = self.r.extern_prelude.get(&ident) { - if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() { - self.r.dcx().emit_err( - errors::MacroExpandedExternCrateCannotShadowExternArguments { - span: item.span, - }, - ); - // `return` is intended to discard this binding because it's an - // unregistered ambiguity error which would result in a panic - // caused by inconsistency `path_res` - // more details: https://github.com/rust-lang/rust/pull/111761 - return; - } + if let Some(entry) = self.r.extern_prelude.get(&ident) + && expansion != LocalExpnId::ROOT + && orig_name.is_some() + && !entry.is_import() + { + self.r.dcx().emit_err( + errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span }, + ); + // `return` is intended to discard this binding because it's an + // unregistered ambiguity error which would result in a panic + // caused by inconsistency `path_res` + // more details: https://github.com/rust-lang/rust/pull/111761 + return; } let entry = self .r @@ -1040,10 +1040,10 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { span: item.span, }); } - if let ItemKind::ExternCrate(Some(orig_name)) = item.kind { - if orig_name == kw::SelfLower { - self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span }); - } + if let ItemKind::ExternCrate(Some(orig_name)) = item.kind + && orig_name == kw::SelfLower + { + self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span }); } let ill_formed = |span| { self.r.dcx().emit_err(errors::BadMacroImport { span }); @@ -1179,14 +1179,12 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { return Some((MacroKind::Bang, item.ident, item.span)); } else if ast::attr::contains_name(&item.attrs, sym::proc_macro_attribute) { return Some((MacroKind::Attr, item.ident, item.span)); - } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(meta_item_inner) = + } else if let Some(attr) = ast::attr::find_by_name(&item.attrs, sym::proc_macro_derive) + && let Some(meta_item_inner) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) - { - if let Some(ident) = meta_item_inner.ident() { - return Some((MacroKind::Derive, ident, ident.span)); - } - } + && let Some(ident) = meta_item_inner.ident() + { + return Some((MacroKind::Derive, ident, ident.span)); } None } diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 5a605df88c2..1c1e8494ffc 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -397,7 +397,7 @@ impl Resolver<'_, '_> { } ImportKind::ExternCrate { id, .. } => { let def_id = self.local_def_id(id); - if self.extern_crate_map.get(&def_id).map_or(true, |&cnum| { + if self.extern_crate_map.get(&def_id).is_none_or(|&cnum| { !tcx.is_compiler_builtins(cnum) && !tcx.is_panic_runtime(cnum) && !tcx.has_global_allocator(cnum) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index dc26d4de57a..43e4e4d591f 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -30,7 +30,7 @@ use rustc_span::hygiene::MacroKind; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym}; use thin_vec::{ThinVec, thin_vec}; -use tracing::debug; +use tracing::{debug, instrument}; use crate::errors::{ self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive, @@ -225,10 +225,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let (name, span) = (ident.name, self.tcx.sess.source_map().guess_head_span(new_binding.span)); - if let Some(s) = self.name_already_seen.get(&name) { - if s == &span { - return; - } + if self.name_already_seen.get(&name) == Some(&span) { + return; } let old_kind = match (ns, old_binding.module()) { @@ -322,7 +320,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let duplicate = new_binding.res().opt_def_id() == old_binding.res().opt_def_id(); let has_dummy_span = new_binding.span.is_dummy() || old_binding.span.is_dummy(); let from_item = - self.extern_prelude.get(&ident).map_or(true, |entry| entry.introduced_by_item); + self.extern_prelude.get(&ident).is_none_or(|entry| entry.introduced_by_item); // Only suggest removing an import if both bindings are to the same def, if both spans // aren't dummy spans. Further, if both bindings are imports, then the ident must have // been introduced by an item. @@ -380,20 +378,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { suggestion = Some(format!("self as {suggested_name}")) } ImportKind::Single { source, .. } => { - if let Some(pos) = - source.span.hi().0.checked_sub(binding_span.lo().0).map(|pos| pos as usize) + if let Some(pos) = source.span.hi().0.checked_sub(binding_span.lo().0) + && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) + && pos as usize <= snippet.len() { - if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(binding_span) { - if pos <= snippet.len() { - span = binding_span - .with_lo(binding_span.lo() + BytePos(pos as u32)) - .with_hi( - binding_span.hi() - - BytePos(if snippet.ends_with(';') { 1 } else { 0 }), - ); - suggestion = Some(format!(" as {suggested_name}")); - } - } + span = binding_span.with_lo(binding_span.lo() + BytePos(pos)).with_hi( + binding_span.hi() - BytePos(if snippet.ends_with(';') { 1 } else { 0 }), + ); + suggestion = Some(format!(" as {suggested_name}")); } } ImportKind::ExternCrate { source, target, .. } => { @@ -510,13 +502,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // If the first element of our path was actually resolved to an // `ExternCrate` (also used for `crate::...`) then no need to issue a // warning, this looks all good! - if let Some(binding) = second_binding { - if let NameBindingKind::Import { import, .. } = binding.kind { - // Careful: we still want to rewrite paths from renamed extern crates. - if let ImportKind::ExternCrate { source: None, .. } = import.kind { - return; - } - } + if let Some(binding) = second_binding + && let NameBindingKind::Import { import, .. } = binding.kind + // Careful: we still want to rewrite paths from renamed extern crates. + && let ImportKind::ExternCrate { source: None, .. } = import.kind + { + return; } let diag = BuiltinLintDiag::AbsPathWithModule(root_span); @@ -537,7 +528,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { module.for_each_child(self, |_this, ident, _ns, binding| { let res = binding.res(); - if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == ident.span.ctxt()) { + if filter_fn(res) && ctxt.is_none_or(|ctxt| ctxt == ident.span.ctxt()) { names.push(TypoSuggestion::typo_from_ident(ident, res)); } }); @@ -1047,20 +1038,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if filter_fn(res) { for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - if let Ok((Some(ext), _)) = this.resolve_macro_path( + let Ok((Some(ext), _)) = this.resolve_macro_path( derive, Some(MacroKind::Derive), parent_scope, false, false, None, - ) { - suggestions.extend( - ext.helper_attrs - .iter() - .map(|name| TypoSuggestion::typo_from_name(*name, res)), - ); - } + ) else { + continue; + }; + suggestions.extend( + ext.helper_attrs + .iter() + .map(|name| TypoSuggestion::typo_from_name(*name, res)), + ); } } } @@ -1215,12 +1207,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } // #90113: Do not count an inaccessible reexported item as a candidate. - if let NameBindingKind::Import { binding, .. } = name_binding.kind { - if this.is_accessible_from(binding.vis, parent_scope.module) - && !this.is_accessible_from(name_binding.vis, parent_scope.module) - { - return; - } + if let NameBindingKind::Import { binding, .. } = name_binding.kind + && this.is_accessible_from(binding.vis, parent_scope.module) + && !this.is_accessible_from(name_binding.vis, parent_scope.module) + { + return; } let res = name_binding.res(); @@ -1229,7 +1220,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => res.opt_def_id(), }; let child_doc_visible = doc_visible - && (did.map_or(true, |did| did.is_local() || !this.tcx.is_doc_hidden(did))); + && did.is_none_or(|did| did.is_local() || !this.tcx.is_doc_hidden(did)); // collect results based on the filter function // avoid suggesting anything from the same module in which we are resolving @@ -1253,14 +1244,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { segms.push(ast::PathSegment::from_ident(ident)); let path = Path { span: name_binding.span, segments: segms, tokens: None }; - if child_accessible { + if child_accessible // Remove invisible match if exists - if let Some(idx) = candidates + && let Some(idx) = candidates .iter() .position(|v: &ImportSuggestion| v.did == did && !v.accessible) - { - candidates.remove(idx); - } + { + candidates.remove(idx); } if candidates.iter().all(|v: &ImportSuggestion| v.did != did) { @@ -1373,48 +1363,50 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // otherwise cause duplicate suggestions. continue; } - let crate_id = self.crate_loader(|c| c.maybe_process_path_extern(ident.name)); - if let Some(crate_id) = crate_id { - let crate_def_id = crate_id.as_def_id(); - let crate_root = self.expect_module(crate_def_id); - - // Check if there's already an item in scope with the same name as the crate. - // If so, we have to disambiguate the potential import suggestions by making - // the paths *global* (i.e., by prefixing them with `::`). - let needs_disambiguation = - self.resolutions(parent_scope.module).borrow().iter().any( - |(key, name_resolution)| { - if key.ns == TypeNS - && key.ident == ident - && let Some(binding) = name_resolution.borrow().binding - { - match binding.res() { - // No disambiguation needed if the identically named item we - // found in scope actually refers to the crate in question. - Res::Def(_, def_id) => def_id != crate_def_id, - Res::PrimTy(_) => true, - _ => false, - } - } else { - false - } - }, - ); - let mut crate_path = ThinVec::new(); - if needs_disambiguation { - crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); - } - crate_path.push(ast::PathSegment::from_ident(ident)); + let Some(crate_id) = self.crate_loader(|c| c.maybe_process_path_extern(ident.name)) + else { + continue; + }; - suggestions.extend(self.lookup_import_candidates_from_module( - lookup_ident, - namespace, - parent_scope, - crate_root, - crate_path, - &filter_fn, - )); + let crate_def_id = crate_id.as_def_id(); + let crate_root = self.expect_module(crate_def_id); + + // Check if there's already an item in scope with the same name as the crate. + // If so, we have to disambiguate the potential import suggestions by making + // the paths *global* (i.e., by prefixing them with `::`). + let needs_disambiguation = + self.resolutions(parent_scope.module).borrow().iter().any( + |(key, name_resolution)| { + if key.ns == TypeNS + && key.ident == ident + && let Some(binding) = name_resolution.borrow().binding + { + match binding.res() { + // No disambiguation needed if the identically named item we + // found in scope actually refers to the crate in question. + Res::Def(_, def_id) => def_id != crate_def_id, + Res::PrimTy(_) => true, + _ => false, + } + } else { + false + } + }, + ); + let mut crate_path = ThinVec::new(); + if needs_disambiguation { + crate_path.push(ast::PathSegment::path_root(rustc_span::DUMMY_SP)); } + crate_path.push(ast::PathSegment::from_ident(ident)); + + suggestions.extend(self.lookup_import_candidates_from_module( + lookup_ident, + namespace, + parent_scope, + crate_root, + crate_path, + &filter_fn, + )); } } @@ -1511,7 +1503,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { - if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( + let Ok(binding) = self.early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns), parent_scope, @@ -1519,53 +1511,53 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { false, None, None, - ) { - let desc = match binding.res() { - Res::Def(DefKind::Macro(MacroKind::Bang), _) => { - "a function-like macro".to_string() - } - Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => { - format!("an attribute: `#[{ident}]`") - } - Res::Def(DefKind::Macro(MacroKind::Derive), _) => { - format!("a derive macro: `#[derive({ident})]`") - } - Res::ToolMod => { - // Don't confuse the user with tool modules. - continue; - } - Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => { - "only a trait, without a derive macro".to_string() - } - res => format!( - "{} {}, not {} {}", - res.article(), - res.descr(), - macro_kind.article(), - macro_kind.descr_expected(), - ), - }; - if let crate::NameBindingKind::Import { import, .. } = binding.kind { - if !import.span.is_dummy() { - let note = errors::IdentImporterHereButItIsDesc { - span: import.span, - imported_ident: ident, - imported_ident_desc: &desc, - }; - err.subdiagnostic(note); - // Silence the 'unused import' warning we might get, - // since this diagnostic already covers that import. - self.record_use(ident, binding, Used::Other); - return; - } + ) else { + continue; + }; + + let desc = match binding.res() { + Res::Def(DefKind::Macro(MacroKind::Bang), _) => "a function-like macro".to_string(), + Res::Def(DefKind::Macro(MacroKind::Attr), _) | Res::NonMacroAttr(..) => { + format!("an attribute: `#[{ident}]`") } - let note = errors::IdentInScopeButItIsDesc { + Res::Def(DefKind::Macro(MacroKind::Derive), _) => { + format!("a derive macro: `#[derive({ident})]`") + } + Res::ToolMod => { + // Don't confuse the user with tool modules. + continue; + } + Res::Def(DefKind::Trait, _) if macro_kind == MacroKind::Derive => { + "only a trait, without a derive macro".to_string() + } + res => format!( + "{} {}, not {} {}", + res.article(), + res.descr(), + macro_kind.article(), + macro_kind.descr_expected(), + ), + }; + if let crate::NameBindingKind::Import { import, .. } = binding.kind + && !import.span.is_dummy() + { + let note = errors::IdentImporterHereButItIsDesc { + span: import.span, imported_ident: ident, imported_ident_desc: &desc, }; err.subdiagnostic(note); + // Silence the 'unused import' warning we might get, + // since this diagnostic already covers that import. + self.record_use(ident, binding, Used::Other); return; } + let note = errors::IdentInScopeButItIsDesc { + imported_ident: ident, + imported_ident_desc: &desc, + }; + err.subdiagnostic(note); + return; } } @@ -1749,15 +1741,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// If the binding refers to a tuple struct constructor with fields, /// returns the span of its fields. fn ctor_fields_span(&self, binding: NameBinding<'_>) -> Option<Span> { - if let NameBindingKind::Res(Res::Def( + let NameBindingKind::Res(Res::Def( DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id, )) = binding.kind - { - let def_id = self.tcx.parent(ctor_def_id); - return self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to); // None for `struct Foo()` - } - None + else { + return None; + }; + + let def_id = self.tcx.parent(ctor_def_id); + self.field_idents(def_id)?.iter().map(|&f| f.span).reduce(Span::to) // None for `struct Foo()` } fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { @@ -1983,10 +1976,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect::<Vec<_>>(); candidates.sort(); candidates.dedup(); - match find_best_match_for_name(&candidates, ident, None) { - Some(sugg) if sugg == ident => None, - sugg => sugg, - } + find_best_match_for_name(&candidates, ident, None).filter(|sugg| *sugg != ident) } pub(crate) fn report_path_resolution_error( @@ -2235,14 +2225,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } /// Adds suggestions for a path that cannot be resolved. + #[instrument(level = "debug", skip(self, parent_scope))] pub(crate) fn make_path_suggestion( &mut self, span: Span, mut path: Vec<Segment>, parent_scope: &ParentScope<'ra>, ) -> Option<(Vec<Segment>, Option<String>)> { - debug!("make_path_suggestion: span={:?} path={:?}", span, path); - match (path.get(0), path.get(1)) { // `{{root}}::ident::...` on both editions. // On 2015 `{{root}}` is usually added implicitly. @@ -2271,6 +2260,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// LL | use foo::Bar; /// | ^^^ did you mean `self::foo`? /// ``` + #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_self_suggestion( &mut self, mut path: Vec<Segment>, @@ -2279,7 +2269,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = kw::SelfLower; let result = self.maybe_resolve_path(&path, None, parent_scope, None); - debug!("make_missing_self_suggestion: path={:?} result={:?}", path, result); + debug!(?path, ?result); if let PathResult::Module(..) = result { Some((path, None)) } else { None } } @@ -2290,6 +2280,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// LL | use foo::Bar; /// | ^^^ did you mean `crate::foo`? /// ``` + #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_crate_suggestion( &mut self, mut path: Vec<Segment>, @@ -2298,7 +2289,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Crate; let result = self.maybe_resolve_path(&path, None, parent_scope, None); - debug!("make_missing_crate_suggestion: path={:?} result={:?}", path, result); + debug!(?path, ?result); if let PathResult::Module(..) = result { Some(( path, @@ -2321,6 +2312,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// LL | use foo::Bar; /// | ^^^ did you mean `super::foo`? /// ``` + #[instrument(level = "debug", skip(self, parent_scope))] fn make_missing_super_suggestion( &mut self, mut path: Vec<Segment>, @@ -2329,7 +2321,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Super; let result = self.maybe_resolve_path(&path, None, parent_scope, None); - debug!("make_missing_super_suggestion: path={:?} result={:?}", path, result); + debug!(?path, ?result); if let PathResult::Module(..) = result { Some((path, None)) } else { None } } @@ -2343,6 +2335,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// /// Used when importing a submodule of an external crate but missing that crate's /// name as the first part of path. + #[instrument(level = "debug", skip(self, parent_scope))] fn make_external_crate_suggestion( &mut self, mut path: Vec<Segment>, @@ -2363,10 +2356,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Replace first ident with a crate name and check if that is valid. path[0].ident.name = name; let result = self.maybe_resolve_path(&path, None, parent_scope, None); - debug!( - "make_external_crate_suggestion: name={:?} path={:?} result={:?}", - name, path, result - ); + debug!(?path, ?name, ?result); if let PathResult::Module(..) = result { return Some((path, None)); } @@ -2410,121 +2400,115 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let binding_key = BindingKey::new(ident, MacroNS); let resolution = resolutions.get(&binding_key)?; let binding = resolution.borrow().binding()?; - if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { - let module_name = crate_module.kind.name().unwrap(); - let import_snippet = match import.kind { - ImportKind::Single { source, target, .. } if source != target => { - format!("{source} as {target}") - } - _ => format!("{ident}"), - }; + let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() else { + return None; + }; + let module_name = crate_module.kind.name().unwrap(); + let import_snippet = match import.kind { + ImportKind::Single { source, target, .. } if source != target => { + format!("{source} as {target}") + } + _ => format!("{ident}"), + }; - let mut corrections: Vec<(Span, String)> = Vec::new(); - if !import.is_nested() { - // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove - // intermediate segments. - corrections.push((import.span, format!("{module_name}::{import_snippet}"))); - } else { - // Find the binding span (and any trailing commas and spaces). - // ie. `use a::b::{c, d, e};` - // ^^^ - let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( - self.tcx.sess, - import.span, - import.use_span, - ); - debug!( - "check_for_module_export_macro: found_closing_brace={:?} binding_span={:?}", - found_closing_brace, binding_span - ); + let mut corrections: Vec<(Span, String)> = Vec::new(); + if !import.is_nested() { + // Assume this is the easy case of `use issue_59764::foo::makro;` and just remove + // intermediate segments. + corrections.push((import.span, format!("{module_name}::{import_snippet}"))); + } else { + // Find the binding span (and any trailing commas and spaces). + // ie. `use a::b::{c, d, e};` + // ^^^ + let (found_closing_brace, binding_span) = find_span_of_binding_until_next_binding( + self.tcx.sess, + import.span, + import.use_span, + ); + debug!(found_closing_brace, ?binding_span); + + let mut removal_span = binding_span; + + // If the binding span ended with a closing brace, as in the below example: + // ie. `use a::b::{c, d};` + // ^ + // Then expand the span of characters to remove to include the previous + // binding's trailing comma. + // ie. `use a::b::{c, d};` + // ^^^ + if found_closing_brace + && let Some(previous_span) = + extend_span_to_previous_binding(self.tcx.sess, binding_span) + { + debug!(?previous_span); + removal_span = removal_span.with_lo(previous_span.lo()); + } + debug!(?removal_span); - let mut removal_span = binding_span; - if found_closing_brace { - // If the binding span ended with a closing brace, as in the below example: - // ie. `use a::b::{c, d};` - // ^ - // Then expand the span of characters to remove to include the previous - // binding's trailing comma. - // ie. `use a::b::{c, d};` - // ^^^ - if let Some(previous_span) = - extend_span_to_previous_binding(self.tcx.sess, binding_span) - { - debug!("check_for_module_export_macro: previous_span={:?}", previous_span); - removal_span = removal_span.with_lo(previous_span.lo()); - } - } - debug!("check_for_module_export_macro: removal_span={:?}", removal_span); - - // Remove the `removal_span`. - corrections.push((removal_span, "".to_string())); - - // Find the span after the crate name and if it has nested imports immediately - // after the crate name already. - // ie. `use a::b::{c, d};` - // ^^^^^^^^^ - // or `use a::{b, c, d}};` - // ^^^^^^^^^^^ - let (has_nested, after_crate_name) = find_span_immediately_after_crate_name( - self.tcx.sess, - module_name, - import.use_span, - ); - debug!( - "check_for_module_export_macro: has_nested={:?} after_crate_name={:?}", - has_nested, after_crate_name - ); + // Remove the `removal_span`. + corrections.push((removal_span, "".to_string())); - let source_map = self.tcx.sess.source_map(); + // Find the span after the crate name and if it has nested imports immediately + // after the crate name already. + // ie. `use a::b::{c, d};` + // ^^^^^^^^^ + // or `use a::{b, c, d}};` + // ^^^^^^^^^^^ + let (has_nested, after_crate_name) = + find_span_immediately_after_crate_name(self.tcx.sess, module_name, import.use_span); + debug!(has_nested, ?after_crate_name); - // Make sure this is actually crate-relative. - let is_definitely_crate = import - .module_path - .first() - .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super); + let source_map = self.tcx.sess.source_map(); - // Add the import to the start, with a `{` if required. - let start_point = source_map.start_point(after_crate_name); - if is_definitely_crate - && let Ok(start_snippet) = source_map.span_to_snippet(start_point) - { - corrections.push(( - start_point, - if has_nested { - // In this case, `start_snippet` must equal '{'. - format!("{start_snippet}{import_snippet}, ") - } else { - // In this case, add a `{`, then the moved import, then whatever - // was there before. - format!("{{{import_snippet}, {start_snippet}") - }, - )); + // Make sure this is actually crate-relative. + let is_definitely_crate = import + .module_path + .first() + .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super); - // Add a `};` to the end if nested, matching the `{` added at the start. - if !has_nested { - corrections - .push((source_map.end_point(after_crate_name), "};".to_string())); - } - } else { - // If the root import is module-relative, add the import separately - corrections.push(( - import.use_span.shrink_to_lo(), - format!("use {module_name}::{import_snippet};\n"), - )); + // Add the import to the start, with a `{` if required. + let start_point = source_map.start_point(after_crate_name); + if is_definitely_crate + && let Ok(start_snippet) = source_map.span_to_snippet(start_point) + { + corrections.push(( + start_point, + if has_nested { + // In this case, `start_snippet` must equal '{'. + format!("{start_snippet}{import_snippet}, ") + } else { + // In this case, add a `{`, then the moved import, then whatever + // was there before. + format!("{{{import_snippet}, {start_snippet}") + }, + )); + + // Add a `};` to the end if nested, matching the `{` added at the start. + if !has_nested { + corrections.push((source_map.end_point(after_crate_name), "};".to_string())); } + } else { + // If the root import is module-relative, add the import separately + corrections.push(( + import.use_span.shrink_to_lo(), + format!("use {module_name}::{import_snippet};\n"), + )); } + } - let suggestion = Some(( - corrections, - String::from("a macro with this name exists at the root of the crate"), - Applicability::MaybeIncorrect, - )); - Some((suggestion, Some("this could be because a macro annotated with `#[macro_export]` will be exported \ + let suggestion = Some(( + corrections, + String::from("a macro with this name exists at the root of the crate"), + Applicability::MaybeIncorrect, + )); + Some(( + suggestion, + Some( + "this could be because a macro annotated with `#[macro_export]` will be exported \ at the root of the crate instead of the module where it is defined" - .to_string()))) - } else { - None - } + .to_string(), + ), + )) } /// Finds a cfg-ed out item inside `module` with the matching name. @@ -2677,15 +2661,12 @@ fn extend_span_to_previous_binding(sess: &Session, binding_span: Span) -> Option /// use foo::{a, b::{c, d}}; /// // ^^^^^^^^^^^^^^^ -- true /// ``` +#[instrument(level = "debug", skip(sess))] fn find_span_immediately_after_crate_name( sess: &Session, module_name: Symbol, use_span: Span, ) -> (bool, Span) { - debug!( - "find_span_immediately_after_crate_name: module_name={:?} use_span={:?}", - module_name, use_span - ); let source_map = sess.source_map(); // Using `use issue_59764::foo::{baz, makro};` as an example throughout.. @@ -3051,7 +3032,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { self.first_legal_span = Some(inject); } self.first_use_span = search_for_any_use_in_items(&c.items); - return; } else { visit::walk_crate(self, c); } @@ -3065,7 +3045,6 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { self.first_legal_span = Some(inject); } self.first_use_span = search_for_any_use_in_items(items); - return; } } else { visit::walk_item(self, item); @@ -3075,16 +3054,16 @@ impl<'tcx> visit::Visitor<'tcx> for UsePlacementFinder { fn search_for_any_use_in_items(items: &[P<ast::Item>]) -> Option<Span> { for item in items { - if let ItemKind::Use(..) = item.kind { - if is_span_suitable_for_use_injection(item.span) { - let mut lo = item.span.lo(); - for attr in &item.attrs { - if attr.span.eq_ctxt(item.span) { - lo = std::cmp::min(lo, attr.span.lo()); - } + if let ItemKind::Use(..) = item.kind + && is_span_suitable_for_use_injection(item.span) + { + let mut lo = item.span.lo(); + for attr in &item.attrs { + if attr.span.eq_ctxt(item.span) { + lo = std::cmp::min(lo, attr.span.lo()); } - return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent())); } + return Some(Span::new(lo, lo, item.span.ctxt(), item.span.parent())); } } None diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index e279d14704e..6ef4aa40725 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -118,37 +118,38 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { let resolutions = self.r.resolutions(module); for (_, name_resolution) in resolutions.borrow().iter() { - if let Some(mut binding) = name_resolution.borrow().binding() { - // Set the given effective visibility level to `Level::Direct` and - // sets the rest of the `use` chain to `Level::Reexported` until - // we hit the actual exported item. - // - // If the binding is ambiguous, put the root ambiguity binding and all reexports - // leading to it into the table. They are used by the `ambiguous_glob_reexports` - // lint. For all bindings added to the table this way `is_ambiguity` returns true. - let is_ambiguity = - |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; - let mut parent_id = ParentId::Def(module_id); - let mut warn_ambiguity = binding.warn_ambiguity; - while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { - self.update_import(binding, parent_id); + let Some(mut binding) = name_resolution.borrow().binding() else { + continue; + }; + // Set the given effective visibility level to `Level::Direct` and + // sets the rest of the `use` chain to `Level::Reexported` until + // we hit the actual exported item. + // + // If the binding is ambiguous, put the root ambiguity binding and all reexports + // leading to it into the table. They are used by the `ambiguous_glob_reexports` + // lint. For all bindings added to the table this way `is_ambiguity` returns true. + let is_ambiguity = + |binding: NameBinding<'ra>, warn: bool| binding.ambiguity.is_some() && !warn; + let mut parent_id = ParentId::Def(module_id); + let mut warn_ambiguity = binding.warn_ambiguity; + while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind { + self.update_import(binding, parent_id); - if is_ambiguity(binding, warn_ambiguity) { - // Stop at the root ambiguity, further bindings in the chain should not - // be reexported because the root ambiguity blocks any access to them. - // (Those further bindings are most likely not ambiguities themselves.) - break; - } - - parent_id = ParentId::Import(binding); - binding = nested_binding; - warn_ambiguity |= nested_binding.warn_ambiguity; - } - if !is_ambiguity(binding, warn_ambiguity) - && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) - { - self.update_def(def_id, binding.vis.expect_local(), parent_id); + if is_ambiguity(binding, warn_ambiguity) { + // Stop at the root ambiguity, further bindings in the chain should not + // be reexported because the root ambiguity blocks any access to them. + // (Those further bindings are most likely not ambiguities themselves.) + break; } + + parent_id = ParentId::Import(binding); + binding = nested_binding; + warn_ambiguity |= nested_binding.warn_ambiguity; + } + if !is_ambiguity(binding, warn_ambiguity) + && let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) + { + self.update_def(def_id, binding.vis.expect_local(), parent_id); } } } diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 45e87edc53e..a3d3e87ade0 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -246,23 +246,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // ---- end // ``` // So we have to fall back to the module's parent during lexical resolution in this case. - if derive_fallback_lint_id.is_some() { - if let Some(parent) = module.parent { - // Inner module is inside the macro, parent module is outside of the macro. - if module.expansion != parent.expansion - && module.expansion.is_descendant_of(parent.expansion) - { - // The macro is a proc macro derive - if let Some(def_id) = module.expansion.expn_data().macro_def_id { - let ext = &self.get_macro_by_def_id(def_id).ext; - if ext.builtin_name.is_none() - && ext.macro_kind() == MacroKind::Derive - && parent.expansion.outer_expn_is_descendant_of(*ctxt) - { - return Some((parent, derive_fallback_lint_id)); - } - } - } + if derive_fallback_lint_id.is_some() + && let Some(parent) = module.parent + // Inner module is inside the macro + && module.expansion != parent.expansion + // Parent module is outside of the macro + && module.expansion.is_descendant_of(parent.expansion) + // The macro is a proc macro derive + && let Some(def_id) = module.expansion.expn_data().macro_def_id + { + let ext = &self.get_macro_by_def_id(def_id).ext; + if ext.builtin_name.is_none() + && ext.macro_kind() == MacroKind::Derive + && parent.expansion.outer_expn_is_descendant_of(*ctxt) + { + return Some((parent, derive_fallback_lint_id)); } } @@ -593,8 +591,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); - if let Some(prelude) = this.prelude { - if let Ok(binding) = this.resolve_ident_in_module_unadjusted( + if let Some(prelude) = this.prelude + && let Ok(binding) = this.resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(prelude), ident, ns, @@ -603,14 +601,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None, ignore_binding, ignore_import, - ) { - if matches!(use_prelude, UsePrelude::Yes) - || this.is_builtin_macro(binding.res()) - { - result = Ok((binding, Flags::MISC_FROM_PRELUDE)); - } - } + ) + && (matches!(use_prelude, UsePrelude::Yes) + || this.is_builtin_macro(binding.res())) + { + result = Ok((binding, Flags::MISC_FROM_PRELUDE)); } + result } Scope::BuiltinTypes => match this.builtin_types_bindings.get(&ident.name) { @@ -939,10 +936,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; // Items and single imports are not shadowable, if we have one, then it's determined. - if let Some(binding) = binding { - if !binding.is_glob_import() { - return check_usable(self, binding); - } + if let Some(binding) = binding + && !binding.is_glob_import() + { + return check_usable(self, binding); } // --- From now on we either have a glob resolution or no resolution. --- @@ -1437,13 +1434,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id); let record_segment_res = |this: &mut Self, res| { - if finalize.is_some() { - if let Some(id) = id { - if !this.partial_res_map.contains_key(&id) { - assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); - this.record_partial_res(id, PartialRes::new(res)); - } - } + if finalize.is_some() + && let Some(id) = id + && !this.partial_res_map.contains_key(&id) + { + assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); + this.record_partial_res(id, PartialRes::new(res)); } }; @@ -1463,13 +1459,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => None, }, }; - if let Some(self_module) = self_module { - if let Some(parent) = self_module.parent { - module = Some(ModuleOrUniformRoot::Module( - self.resolve_self(&mut ctxt, parent), - )); - continue; - } + if let Some(self_module) = self_module + && let Some(parent) = self_module.parent + { + module = + Some(ModuleOrUniformRoot::Module(self.resolve_self(&mut ctxt, parent))); + continue; } return PathResult::failed( ident, @@ -1644,13 +1639,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } Err(Undetermined) => return PathResult::Indeterminate, Err(Determined) => { - if let Some(ModuleOrUniformRoot::Module(module)) = module { - if opt_ns.is_some() && !module.is_normal() { - return PathResult::NonModule(PartialRes::with_unresolved_segments( - module.res().unwrap(), - path.len() - segment_idx, - )); - } + if let Some(ModuleOrUniformRoot::Module(module)) = module + && opt_ns.is_some() + && !module.is_normal() + { + return PathResult::NonModule(PartialRes::with_unresolved_segments( + module.res().unwrap(), + path.len() - segment_idx, + )); } return PathResult::failed( diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index cad45d3c293..d555c938770 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -287,12 +287,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding.vis }; - if let ImportKind::Glob { ref max_vis, .. } = import.kind { - if vis == import_vis - || max_vis.get().map_or(true, |max_vis| vis.is_at_least(max_vis, self.tcx)) - { - max_vis.set(Some(vis.expect_local())) - } + if let ImportKind::Glob { ref max_vis, .. } = import.kind + && (vis == import_vis + || max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx))) + { + max_vis.set(Some(vis.expect_local())) } self.arenas.alloc_name_binding(NameBindingData { @@ -543,31 +542,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // resolution for it so that later resolve stages won't complain. self.import_dummy_binding(*import, is_indeterminate); - if let Some(err) = unresolved_import_error { - glob_error |= import.is_glob(); + let Some(err) = unresolved_import_error else { continue }; - if let ImportKind::Single { source, ref source_bindings, .. } = import.kind { - if source.name == kw::SelfLower { - // Silence `unresolved import` error if E0429 is already emitted - if let Err(Determined) = source_bindings.value_ns.get() { - continue; - } - } - } + glob_error |= import.is_glob(); - if prev_root_id != NodeId::ZERO - && prev_root_id != import.root_id - && !errors.is_empty() - { - // In the case of a new import line, throw a diagnostic message - // for the previous line. - self.throw_unresolved_import_error(errors, glob_error); - errors = vec![]; - } - if seen_spans.insert(err.span) { - errors.push((*import, err)); - prev_root_id = import.root_id; - } + if let ImportKind::Single { source, ref source_bindings, .. } = import.kind + && source.name == kw::SelfLower + // Silence `unresolved import` error if E0429 is already emitted + && let Err(Determined) = source_bindings.value_ns.get() + { + continue; + } + + if prev_root_id != NodeId::ZERO && prev_root_id != import.root_id && !errors.is_empty() + { + // In the case of a new import line, throw a diagnostic message + // for the previous line. + self.throw_unresolved_import_error(errors, glob_error); + errors = vec![]; + } + if seen_spans.insert(err.span) { + errors.push((*import, err)); + prev_root_id = import.root_id; } } @@ -609,60 +605,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - if let Some(binding) = resolution.binding { - if let NameBindingKind::Import { import, .. } = binding.kind - && let Some((amb_binding, _)) = binding.ambiguity - && binding.res() != Res::Err - && exported_ambiguities.contains(&binding) + let Some(binding) = resolution.binding else { continue }; + + if let NameBindingKind::Import { import, .. } = binding.kind + && let Some((amb_binding, _)) = binding.ambiguity + && binding.res() != Res::Err + && exported_ambiguities.contains(&binding) + { + self.lint_buffer.buffer_lint( + AMBIGUOUS_GLOB_REEXPORTS, + import.root_id, + import.root_span, + BuiltinLintDiag::AmbiguousGlobReexports { + name: key.ident.to_string(), + namespace: key.ns.descr().to_string(), + first_reexport_span: import.root_span, + duplicate_reexport_span: amb_binding.span, + }, + ); + } + + if let Some(glob_binding) = resolution.shadowed_glob { + let binding_id = match binding.kind { + NameBindingKind::Res(res) => { + Some(self.def_id_to_node_id[res.def_id().expect_local()]) + } + NameBindingKind::Module(module) => { + Some(self.def_id_to_node_id[module.def_id().expect_local()]) + } + NameBindingKind::Import { import, .. } => import.id(), + }; + + if binding.res() != Res::Err + && glob_binding.res() != Res::Err + && let NameBindingKind::Import { import: glob_import, .. } = + glob_binding.kind + && let Some(binding_id) = binding_id + && let Some(glob_import_id) = glob_import.id() + && let glob_import_def_id = self.local_def_id(glob_import_id) + && self.effective_visibilities.is_exported(glob_import_def_id) + && glob_binding.vis.is_public() + && !binding.vis.is_public() { self.lint_buffer.buffer_lint( - AMBIGUOUS_GLOB_REEXPORTS, - import.root_id, - import.root_span, - BuiltinLintDiag::AmbiguousGlobReexports { - name: key.ident.to_string(), - namespace: key.ns.descr().to_string(), - first_reexport_span: import.root_span, - duplicate_reexport_span: amb_binding.span, + HIDDEN_GLOB_REEXPORTS, + binding_id, + binding.span, + BuiltinLintDiag::HiddenGlobReexports { + name: key.ident.name.to_string(), + namespace: key.ns.descr().to_owned(), + glob_reexport_span: glob_binding.span, + private_item_span: binding.span, }, ); } - - if let Some(glob_binding) = resolution.shadowed_glob { - let binding_id = match binding.kind { - NameBindingKind::Res(res) => { - Some(self.def_id_to_node_id[res.def_id().expect_local()]) - } - NameBindingKind::Module(module) => { - Some(self.def_id_to_node_id[module.def_id().expect_local()]) - } - NameBindingKind::Import { import, .. } => import.id(), - }; - - if binding.res() != Res::Err - && glob_binding.res() != Res::Err - && let NameBindingKind::Import { import: glob_import, .. } = - glob_binding.kind - && let Some(binding_id) = binding_id - && let Some(glob_import_id) = glob_import.id() - && let glob_import_def_id = self.local_def_id(glob_import_id) - && self.effective_visibilities.is_exported(glob_import_def_id) - && glob_binding.vis.is_public() - && !binding.vis.is_public() - { - self.lint_buffer.buffer_lint( - HIDDEN_GLOB_REEXPORTS, - binding_id, - binding.span, - BuiltinLintDiag::HiddenGlobReexports { - name: key.ident.name.to_string(), - namespace: key.ns.descr().to_owned(), - glob_reexport_span: glob_binding.span, - private_item_span: binding.span, - }, - ); - } - } } } } @@ -1006,21 +1002,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); } - if let ModuleOrUniformRoot::Module(module) = module { - if module == import.parent_scope.module { - // Importing a module into itself is not allowed. - return Some(UnresolvedImportError { - span: import.span, - label: Some(String::from( - "cannot glob-import a module into itself", - )), - note: None, - suggestion: None, - candidates: None, - segment: None, - module: None, - }); - } + if let ModuleOrUniformRoot::Module(module) = module + && module == import.parent_scope.module + { + // Importing a module into itself is not allowed. + return Some(UnresolvedImportError { + span: import.span, + label: Some(String::from("cannot glob-import a module into itself")), + note: None, + suggestion: None, + candidates: None, + segment: None, + module: None, + }); } if !is_prelude && let Some(max_vis) = max_vis.get() @@ -1081,18 +1075,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Consistency checks, analogous to `finalize_macro_resolutions`. let initial_res = source_bindings[ns].get().map(|initial_binding| { all_ns_err = false; - if let Some(target_binding) = target_bindings[ns].get() { - if target.name == kw::Underscore - && initial_binding.is_extern_crate() - && !initial_binding.is_import() - { - let used = if import.module_path.is_empty() { - Used::Scope - } else { - Used::Other - }; - this.record_use(ident, target_binding, used); - } + if let Some(target_binding) = target_bindings[ns].get() + && target.name == kw::Underscore + && initial_binding.is_extern_crate() + && !initial_binding.is_import() + { + let used = if import.module_path.is_empty() { + Used::Scope + } else { + Used::Other + }; + this.record_use(ident, target_binding, used); } initial_binding.res() }); @@ -1247,17 +1240,19 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut any_successful_reexport = false; let mut crate_private_reexport = false; self.per_ns(|this, ns| { - if let Ok(binding) = source_bindings[ns].get() { - if !binding.vis.is_at_least(import.vis, this.tcx) { - reexport_error = Some((ns, binding)); - if let ty::Visibility::Restricted(binding_def_id) = binding.vis { - if binding_def_id.is_top_level_module() { - crate_private_reexport = true; - } - } - } else { - any_successful_reexport = true; + let Ok(binding) = source_bindings[ns].get() else { + return; + }; + + if !binding.vis.is_at_least(import.vis, this.tcx) { + reexport_error = Some((ns, binding)); + if let ty::Visibility::Restricted(binding_def_id) = binding.vis + && binding_def_id.is_top_level_module() + { + crate_private_reexport = true; } + } else { + any_successful_reexport = true; } }); @@ -1474,28 +1469,28 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Since import resolution is finished, globs will not define any more names. *module.globs.borrow_mut() = Vec::new(); - if let Some(def_id) = module.opt_def_id() { - let mut children = Vec::new(); - - module.for_each_child(self, |this, ident, _, binding| { - let res = binding.res().expect_non_local(); - let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity; - if res != def::Res::Err && !error_ambiguity { - let mut reexport_chain = SmallVec::new(); - let mut next_binding = binding; - while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { - reexport_chain.push(import.simplify(this)); - next_binding = binding; - } + let Some(def_id) = module.opt_def_id() else { return }; + + let mut children = Vec::new(); - children.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); + module.for_each_child(self, |this, ident, _, binding| { + let res = binding.res().expect_non_local(); + let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity; + if res != def::Res::Err && !error_ambiguity { + let mut reexport_chain = SmallVec::new(); + let mut next_binding = binding; + while let NameBindingKind::Import { binding, import, .. } = next_binding.kind { + reexport_chain.push(import.simplify(this)); + next_binding = binding; } - }); - if !children.is_empty() { - // Should be fine because this code is only called for local modules. - self.module_children.insert(def_id.expect_local(), children); + children.push(ModChild { ident, res, vis: binding.vis, reexport_chain }); } + }); + + if !children.is_empty() { + // Should be fine because this code is only called for local modules. + self.module_children.insert(def_id.expect_local(), children); } } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index c4aeaf478bd..8bd40ed3a73 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -468,16 +468,12 @@ impl<'a> PathSource<'a> { { "external crate" } - ExprKind::Path(_, path) => { - let mut msg = "function"; - if let Some(segment) = path.segments.iter().last() { - if let Some(c) = segment.ident.to_string().chars().next() { - if c.is_uppercase() { - msg = "function, tuple struct or tuple variant"; - } - } - } - msg + ExprKind::Path(_, path) + if let Some(segment) = path.segments.last() + && let Some(c) = segment.ident.to_string().chars().next() + && c.is_uppercase() => + { + "function, tuple struct or tuple variant" } _ => "function", }, @@ -612,7 +608,7 @@ impl MaybeExported<'_> { return vis.kind.is_pub(); } }; - def_id.map_or(true, |def_id| r.effective_visibilities.is_exported(def_id)) + def_id.is_none_or(|def_id| r.effective_visibilities.is_exported(def_id)) } } @@ -1182,32 +1178,27 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r // namespace first, and if that fails we try again in the value namespace. If // resolution in the value namespace succeeds, we have an generic const argument on // our hands. - if let TyKind::Path(None, ref path) = ty.kind { + if let TyKind::Path(None, ref path) = ty.kind // We cannot disambiguate multi-segment paths right now as that requires type // checking. - if path.is_potential_trivial_const_arg() { - let mut check_ns = |ns| { - self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) - .is_some() - }; - if !check_ns(TypeNS) && check_ns(ValueNS) { - self.resolve_anon_const_manual( - true, - AnonConstKind::ConstArg(IsRepeatExpr::No), - |this| { - this.smart_resolve_path( - ty.id, - &None, - path, - PathSource::Expr(None), - ); - this.visit_path(path, ty.id); - }, - ); + && path.is_potential_trivial_const_arg() + { + let mut check_ns = |ns| { + self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns) + .is_some() + }; + if !check_ns(TypeNS) && check_ns(ValueNS) { + self.resolve_anon_const_manual( + true, + AnonConstKind::ConstArg(IsRepeatExpr::No), + |this| { + this.smart_resolve_path(ty.id, &None, path, PathSource::Expr(None)); + this.visit_path(path, ty.id); + }, + ); - self.diag_metadata.currently_processing_generic_args = prev; - return; - } + self.diag_metadata.currently_processing_generic_args = prev; + return; } } @@ -1243,54 +1234,56 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r } fn visit_path_segment(&mut self, path_segment: &'ast PathSegment) { - if let Some(ref args) = path_segment.args { - match &**args { - GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args), - GenericArgs::Parenthesized(p_args) => { - // Probe the lifetime ribs to know how to behave. - for rib in self.lifetime_ribs.iter().rev() { - match rib.kind { - // We are inside a `PolyTraitRef`. The lifetimes are - // to be introduced in that (maybe implicit) `for<>` binder. - LifetimeRibKind::Generics { - binder, - kind: LifetimeBinderKind::PolyTrait, - .. - } => { - self.with_lifetime_rib( - LifetimeRibKind::AnonymousCreateParameter { + let Some(ref args) = path_segment.args else { + return; + }; + + match &**args { + GenericArgs::AngleBracketed(..) => visit::walk_generic_args(self, args), + GenericArgs::Parenthesized(p_args) => { + // Probe the lifetime ribs to know how to behave. + for rib in self.lifetime_ribs.iter().rev() { + match rib.kind { + // We are inside a `PolyTraitRef`. The lifetimes are + // to be introduced in that (maybe implicit) `for<>` binder. + LifetimeRibKind::Generics { + binder, + kind: LifetimeBinderKind::PolyTrait, + .. + } => { + self.with_lifetime_rib( + LifetimeRibKind::AnonymousCreateParameter { + binder, + report_in_path: false, + }, + |this| { + this.resolve_fn_signature( binder, - report_in_path: false, - }, - |this| { - this.resolve_fn_signature( - binder, - false, - p_args.inputs.iter().map(|ty| (None, &**ty)), - &p_args.output, - ) - }, - ); - break; - } - // We have nowhere to introduce generics. Code is malformed, - // so use regular lifetime resolution to avoid spurious errors. - LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { - visit::walk_generic_args(self, args); - break; - } - LifetimeRibKind::AnonymousCreateParameter { .. } - | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } - | LifetimeRibKind::Elided(_) - | LifetimeRibKind::ElisionFailure - | LifetimeRibKind::ConcreteAnonConst(_) - | LifetimeRibKind::ConstParamTy => {} + false, + p_args.inputs.iter().map(|ty| (None, &**ty)), + &p_args.output, + ) + }, + ); + break; + } + // We have nowhere to introduce generics. Code is malformed, + // so use regular lifetime resolution to avoid spurious errors. + LifetimeRibKind::Item | LifetimeRibKind::Generics { .. } => { + visit::walk_generic_args(self, args); + break; } + LifetimeRibKind::AnonymousCreateParameter { .. } + | LifetimeRibKind::AnonymousReportError + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } + | LifetimeRibKind::Elided(_) + | LifetimeRibKind::ElisionFailure + | LifetimeRibKind::ConcreteAnonConst(_) + | LifetimeRibKind::ConstParamTy => {} } } - GenericArgs::ParenthesizedElided(_) => {} } + GenericArgs::ParenthesizedElided(_) => {} } } @@ -1735,13 +1728,8 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } let normalized_ident = ident.normalize_to_macros_2_0(); - let mut outer_res = None; - for rib in lifetime_rib_iter { - if let Some((&outer, _)) = rib.bindings.get_key_value(&normalized_ident) { - outer_res = Some(outer); - break; - } - } + let outer_res = lifetime_rib_iter + .find_map(|rib| rib.bindings.get_key_value(&normalized_ident).map(|(&outer, _)| outer)); self.emit_undeclared_lifetime_error(lifetime, outer_res); self.record_lifetime_res(lifetime.id, LifetimeRes::Error, LifetimeElisionCandidate::Named); @@ -1808,23 +1796,21 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } LifetimeRibKind::AnonymousReportError => { if elided { - let mut suggestion = None; - for rib in self.lifetime_ribs[i..].iter().rev() { + let suggestion = self.lifetime_ribs[i..].iter().rev().find_map(|rib| { if let LifetimeRibKind::Generics { span, kind: LifetimeBinderKind::PolyTrait | LifetimeBinderKind::WhereBound, .. - } = &rib.kind + } = rib.kind { - suggestion = - Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { - lo: span.shrink_to_lo(), - hi: lifetime.ident.span.shrink_to_hi(), - }); - break; + Some(errors::ElidedAnonymousLivetimeReportErrorSuggestion { + lo: span.shrink_to_lo(), + hi: lifetime.ident.span.shrink_to_hi(), + }) + } else { + None } - } - + }); // are we trying to use an anonymous lifetime // on a non GAT associated trait type? if !self.in_func_body @@ -2460,12 +2446,12 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { for i in (0..self.label_ribs.len()).rev() { let rib = &self.label_ribs[i]; - if let RibKind::MacroDefinition(def) = rib.kind { + if let RibKind::MacroDefinition(def) = rib.kind // If an invocation of this macro created `ident`, give up on `ident` // and switch to `ident`'s source from the macro definition. - if def == self.r.macro_def(label.span.ctxt()) { - label.span.remove_mark(); - } + && def == self.r.macro_def(label.span.ctxt()) + { + label.span.remove_mark(); } let ident = label.normalize_to_macro_rules(); @@ -2493,14 +2479,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { /// Determine whether or not a label from the `rib_index`th label rib is reachable. fn is_label_valid_from_rib(&self, rib_index: usize) -> bool { let ribs = &self.label_ribs[rib_index + 1..]; - - for rib in ribs { - if rib.kind.is_label_barrier() { - return false; - } - } - - true + ribs.iter().all(|rib| !rib.kind.is_label_barrier()) } fn resolve_adt(&mut self, item: &'ast Item, generics: &'ast Generics) { @@ -3505,21 +3484,20 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.visit_ty(&qself.ty); } self.visit_path(&delegation.path, delegation.id); - if let Some(body) = &delegation.body { - self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { - // `PatBoundCtx` is not necessary in this context - let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; - - let span = delegation.path.segments.last().unwrap().ident.span; - this.fresh_binding( - Ident::new(kw::SelfLower, span), - delegation.id, - PatternSource::FnParam, - &mut bindings, - ); - this.visit_block(body); - }); - } + let Some(body) = &delegation.body else { return }; + self.with_rib(ValueNS, RibKind::FnOrCoroutine, |this| { + // `PatBoundCtx` is not necessary in this context + let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())]; + + let span = delegation.path.segments.last().unwrap().ident.span; + this.fresh_binding( + Ident::new(kw::SelfLower, span), + delegation.id, + PatternSource::FnParam, + &mut bindings, + ); + this.visit_block(body); + }); } fn resolve_params(&mut self, params: &'ast [Param]) { @@ -3960,7 +3938,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { match res { Res::SelfCtor(_) // See #70549. | Res::Def( - DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::ConstParam, + DefKind::Ctor(_, CtorKind::Const) | DefKind::Const | DefKind::AssocConst | DefKind::ConstParam, _, ) if is_syntactic_ambiguity => { // Disambiguate in favor of a unit struct/variant or constant pattern. @@ -3969,7 +3947,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { } Some(res) } - Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::Static { .. }, _) => { + Res::Def(DefKind::Ctor(..) | DefKind::Const | DefKind::AssocConst | DefKind::Static { .. }, _) => { // This is unambiguously a fresh binding, either syntactically // (e.g., `IDENT @ PAT` or `ref IDENT`) or because `IDENT` resolves // to something unusable as a pattern (e.g., constructor function), @@ -4005,7 +3983,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ); None } - Res::Def(DefKind::Fn, _) | Res::Local(..) | Res::Err => { + Res::Def(DefKind::Fn | DefKind::AssocFn, _) | Res::Local(..) | Res::Err => { // These entities are explicitly allowed to be shadowed by fresh bindings. None } @@ -5104,7 +5082,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { 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) { + if !tcx.opt_item_name(def_id).is_some_and(|n| n.as_str() == *next_step) { return false; } def_id = parent; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2936d722aa7..17c92c7b501 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1696,7 +1696,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { ) => { // Don't suggest macro if it's unstable. let suggestable = def_id.is_local() - || self.r.tcx.lookup_stability(def_id).map_or(true, |s| s.is_stable()); + || self.r.tcx.lookup_stability(def_id).is_none_or(|s| s.is_stable()); err.span_label(span, fallback_label.to_string()); @@ -2135,7 +2135,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .r .delegation_fn_sigs .get(&self.r.local_def_id(assoc_item.id)) - .map_or(false, |sig| sig.has_self) => + .is_some_and(|sig| sig.has_self) => { AssocSuggestion::MethodWithSelf { called } } @@ -2166,7 +2166,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { .r .delegation_fn_sigs .get(&def_id) - .map_or(false, |sig| sig.has_self), + .is_some_and(|sig| sig.has_self), None => self .r .tcx diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8e457e68eec..3b18e480be4 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1242,7 +1242,7 @@ impl<'ra> ResolverArenas<'ra> { no_implicit_prelude, )))); let def_id = module.opt_def_id(); - if def_id.map_or(true, |def_id| def_id.is_local()) { + if def_id.is_none_or(|def_id| def_id.is_local()) { self.local_modules.borrow_mut().push(module); } if let Some(def_id) = def_id { diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 25e35fead7e..4ff54f47435 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -6,15 +6,14 @@ use std::mem; use rustc_ast::attr::AttributeExt; use rustc_ast::expand::StrippedCfgItem; -use rustc_ast::{self as ast, Crate, Inline, ItemKind, ModKind, NodeId, attr}; +use rustc_ast::{self as ast, Crate, NodeId, attr}; use rustc_ast_pretty::pprust; use rustc_attr_parsing::StabilityLevel; use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_errors::{Applicability, StashKey}; use rustc_expand::base::{ - Annotatable, DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, - SyntaxExtensionKind, + DeriveResolution, Indeterminate, ResolverExpand, SyntaxExtension, SyntaxExtensionKind, }; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{ @@ -26,8 +25,8 @@ use rustc_middle::middle::stability; use rustc_middle::ty::{RegisteredTools, TyCtxt, Visibility}; use rustc_session::lint::BuiltinLintDiag; use rustc_session::lint::builtin::{ - LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, SOFT_UNSTABLE, - UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_MACRO_RULES, UNUSED_MACROS, + LEGACY_DERIVE_HELPERS, OUT_OF_SCOPE_MACRO_CALLS, UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, + UNUSED_MACRO_RULES, UNUSED_MACROS, }; use rustc_session::parse::feature_err; use rustc_span::edit_distance::edit_distance; @@ -157,26 +156,6 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools { registered_tools } -// Some feature gates for inner attributes are reported as lints for backward compatibility. -fn soft_custom_inner_attributes_gate(path: &ast::Path, invoc: &Invocation) -> bool { - match &path.segments[..] { - // `#![test]` - [seg] if seg.ident.name == sym::test => return true, - // `#![rustfmt::skip]` on out-of-line modules - [seg1, seg2] if seg1.ident.name == sym::rustfmt && seg2.ident.name == sym::skip => { - if let InvocationKind::Attr { item, .. } = &invoc.kind { - if let Annotatable::Item(item) = item { - if let ItemKind::Mod(_, ModKind::Loaded(_, Inline::No, _, _)) = item.kind { - return true; - } - } - } - } - _ => {} - } - false -} - impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { fn next_node_id(&mut self) -> NodeId { self.next_node_id() @@ -317,7 +296,6 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { parent_scope, node_id, force, - soft_custom_inner_attributes_gate(path, invoc), deleg_impl, looks_like_invoc_in_mod_inert_attr, )?; @@ -549,7 +527,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { parent_scope: &ParentScope<'ra>, node_id: NodeId, force: bool, - soft_custom_inner_attributes_gate: bool, deleg_impl: Option<LocalDefId>, invoc_in_mod_inert_attr: Option<LocalDefId>, ) -> Result<(Lrc<SyntaxExtension>, Res), Indeterminate> { @@ -667,22 +644,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Res::NonMacroAttr(..) => false, _ => unreachable!(), }; - if soft_custom_inner_attributes_gate { - self.tcx.sess.psess.buffer_lint( - SOFT_UNSTABLE, - path.span, - node_id, - BuiltinLintDiag::InnerAttributeUnstable { is_macro }, - ); + let msg = if is_macro { + "inner macro attributes are unstable" } else { - // FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::InnerAttributeUnstable`) - let msg = if is_macro { - "inner macro attributes are unstable" - } else { - "custom inner attributes are unstable" - }; - feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit(); - } + "custom inner attributes are unstable" + }; + feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit(); } if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) @@ -1055,7 +1022,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { span: Span, ) { if let Some(Res::NonMacroAttr(kind)) = res { - if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) { + if kind != NonMacroAttrKind::Tool && binding.is_none_or(|b| b.is_import()) { let binding_span = binding.map(|binding| binding.span); self.dcx().emit_err(errors::CannotUseThroughAnImport { span, diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs index 7998596c59e..fecb9735019 100644 --- a/compiler/rustc_resolve/src/rustdoc.rs +++ b/compiler/rustc_resolve/src/rustdoc.rs @@ -350,10 +350,7 @@ pub fn strip_generics_from_path(path_str: &str) -> Result<Box<str>, MalformedGen /// If there are no doc-comments, return true. /// FIXME(#78591): Support both inner and outer attributes on the same item. pub fn inner_docs(attrs: &[impl AttributeExt]) -> bool { - attrs - .iter() - .find(|a| a.doc_str().is_some()) - .map_or(true, |a| a.style() == ast::AttrStyle::Inner) + attrs.iter().find(|a| a.doc_str().is_some()).is_none_or(|a| a.style() == ast::AttrStyle::Inner) } /// Has `#[rustc_doc_primitive]` or `#[doc(keyword)]`. diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml index e9983699609..b9c535df4bd 100644 --- a/compiler/rustc_session/Cargo.toml +++ b/compiler/rustc_session/Cargo.toml @@ -31,7 +31,7 @@ libc = "0.2" # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_System_LibraryLoader", diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 21afb7df7cb..97bd2670aa6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -675,7 +675,7 @@ impl OutputTypes { /// Returns `true` if user specified a name and not just produced type pub fn contains_explicit_name(&self, key: &OutputType) -> bool { - self.0.get(key).map_or(false, |f| f.is_some()) + matches!(self.0.get(key), Some(Some(..))) } pub fn iter(&self) -> BTreeMapIter<'_, OutputType, Option<OutFileName>> { @@ -888,7 +888,7 @@ impl Input { Input::File(file) => Some(file), Input::Str { name, .. } => match name { FileName::Real(real) => real.local_path(), - FileName::QuoteExpansion(_) => None, + FileName::CfgSpec(_) => None, FileName::Anon(_) => None, FileName::MacroExpansion(_) => None, FileName::ProcMacroSourceCode(_) => None, @@ -1268,7 +1268,6 @@ pub enum EntryFnType { /// and an `include!()`. sigpipe: u8, }, - Start, } #[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] @@ -1346,8 +1345,12 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg { user_cfg } -pub fn build_target_config(early_dcx: &EarlyDiagCtxt, opts: &Options, sysroot: &Path) -> Target { - match Target::search(&opts.target_triple, sysroot) { +pub fn build_target_config( + early_dcx: &EarlyDiagCtxt, + target: &TargetTuple, + sysroot: &Path, +) -> Target { + match Target::search(target, sysroot) { Ok((target, warnings)) => { for warning in warnings.warning_messages() { early_dcx.early_warn(warning) @@ -1951,7 +1954,7 @@ fn collect_print_requests( matches: &getopts::Matches, ) -> Vec<PrintRequest> { let mut prints = Vec::<PrintRequest>::new(); - if cg.target_cpu.as_ref().is_some_and(|s| s == "help") { + if cg.target_cpu.as_deref() == Some("help") { prints.push(PrintRequest { kind: PrintKind::TargetCPUs, out: OutFileName::Stdout }); cg.target_cpu = None; }; diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 4be013fd6fd..ec83761da4a 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -145,7 +145,7 @@ fn current_dll_path() -> Result<PathBuf, String> { .map_err(|e| e.to_string())?; let mut filename = vec![0; 1024]; - let n = unsafe { GetModuleFileNameW(module, &mut filename) } as usize; + let n = unsafe { GetModuleFileNameW(Some(module), &mut filename) } as usize; if n == 0 { return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error())); } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 60f1154dc6d..10f1ce376ef 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -189,7 +189,7 @@ pub struct Session { /// enabled. Makes it so that "please report a bug" is hidden, as ICEs with /// internal features are wontfix, and they are usually the cause of the ICEs. /// None signifies that this is not tracked. - pub using_internal_features: Arc<AtomicBool>, + pub using_internal_features: &'static AtomicBool, /// All commandline args used to invoke the compiler, with @file args fully expanded. /// This will only be used within debug info, e.g. in the pdb file on windows @@ -966,7 +966,7 @@ pub fn build_session( sysroot: PathBuf, cfg_version: &'static str, ice_file: Option<PathBuf>, - using_internal_features: Arc<AtomicBool>, + using_internal_features: &'static AtomicBool, expanded_args: Vec<String>, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs index dc63ea1999e..ad38ea228bf 100644 --- a/compiler/rustc_smir/src/rustc_internal/mod.rs +++ b/compiler/rustc_smir/src/rustc_internal/mod.rs @@ -316,7 +316,7 @@ macro_rules! optional { #[doc(hidden)] macro_rules! run_driver { ($args:expr, $callback:expr $(, $with_tcx:ident)?) => {{ - use rustc_driver::{Callbacks, Compilation, RunCompiler}; + use rustc_driver::{Callbacks, Compilation, run_compiler}; use rustc_middle::ty::TyCtxt; use rustc_interface::interface; use stable_mir::CompilerError; @@ -347,7 +347,7 @@ macro_rules! run_driver { /// Runs the compiler against given target and tests it with `test_function` pub fn run(&mut self) -> Result<C, CompilerError<B>> { let compiler_result = rustc_driver::catch_fatal_errors(|| -> interface::Result::<()> { - RunCompiler::new(&self.args.clone(), self).run(); + run_compiler(&self.args.clone(), self); Ok(()) }); match (compiler_result, self.result.take()) { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index de933952c6a..a5a17b4b573 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -181,6 +181,7 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { RawPtr(mutability, place) => { stable_mir::mir::Rvalue::AddressOf(mutability.stable(tables), place.stable(tables)) } + Len(place) => stable_mir::mir::Rvalue::Len(place.stable(tables)), Cast(cast_kind, op, ty) => stable_mir::mir::Rvalue::Cast( cast_kind.stable(tables), op.stable(tables), diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index 3cdae437b7d..a5826137181 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -1163,9 +1163,6 @@ pub enum DesugaringKind { WhileLoop, /// `async Fn()` bound modifier BoundModifier, - /// Marks a `&raw const *_1` needed as part of getting the length of a mutable - /// slice for the bounds check, so that MIRI's retag handling can recognize it. - IndexBoundsCheckReborrow, } impl DesugaringKind { @@ -1182,7 +1179,6 @@ impl DesugaringKind { DesugaringKind::ForLoop => "`for` loop", DesugaringKind::WhileLoop => "`while` loop", DesugaringKind::BoundModifier => "trait bound modifier", - DesugaringKind::IndexBoundsCheckReborrow => "slice indexing", } } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 51cfbf59471..51d809bd65d 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -25,6 +25,7 @@ #![feature(hash_set_entry)] #![feature(if_let_guard)] #![feature(let_chains)] +#![feature(map_try_insert)] #![feature(negative_impls)] #![feature(read_buf)] #![feature(round_char_boundary)] @@ -85,9 +86,9 @@ use std::str::FromStr; use std::{fmt, iter}; use md5::{Digest, Md5}; -use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{Hash64, Hash128, HashStable, StableHasher}; use rustc_data_structures::sync::{FreezeLock, FreezeWriteGuard, Lock, Lrc}; +use rustc_data_structures::unord::UnordMap; use sha1::Sha1; use sha2::Sha256; @@ -103,7 +104,7 @@ pub struct SessionGlobals { span_interner: Lock<span_encoding::SpanInterner>, /// Maps a macro argument token into use of the corresponding metavariable in the macro body. /// Collisions are possible and processed in `maybe_use_metavar_location` on best effort basis. - metavar_spans: Lock<FxHashMap<Span, Span>>, + metavar_spans: MetavarSpansMap, hygiene_data: Lock<hygiene::HygieneData>, /// The session's source map, if there is one. This field should only be @@ -177,9 +178,42 @@ pub fn create_default_session_globals_then<R>(f: impl FnOnce() -> R) -> R { // deserialization. scoped_tls::scoped_thread_local!(static SESSION_GLOBALS: SessionGlobals); +#[derive(Default)] +pub struct MetavarSpansMap(FreezeLock<UnordMap<Span, (Span, bool)>>); + +impl MetavarSpansMap { + pub fn insert(&self, span: Span, var_span: Span) -> bool { + match self.0.write().try_insert(span, (var_span, false)) { + Ok(_) => true, + Err(entry) => entry.entry.get().0 == var_span, + } + } + + /// Read a span and record that it was read. + pub fn get(&self, span: Span) -> Option<Span> { + if let Some(mut mspans) = self.0.try_write() { + if let Some((var_span, read)) = mspans.get_mut(&span) { + *read = true; + Some(*var_span) + } else { + None + } + } else { + if let Some((span, true)) = self.0.read().get(&span) { Some(*span) } else { None } + } + } + + /// Freeze the set, and return the spans which have been read. + /// + /// After this is frozen, no spans that have not been read can be read. + pub fn freeze_and_get_read_spans(&self) -> UnordMap<Span, Span> { + self.0.freeze().items().filter(|(_, (_, b))| *b).map(|(s1, (s2, _))| (*s1, *s2)).collect() + } +} + #[inline] -pub fn with_metavar_spans<R>(f: impl FnOnce(&mut FxHashMap<Span, Span>) -> R) -> R { - with_session_globals(|session_globals| f(&mut session_globals.metavar_spans.lock())) +pub fn with_metavar_spans<R>(f: impl FnOnce(&MetavarSpansMap) -> R) -> R { + with_session_globals(|session_globals| f(&session_globals.metavar_spans)) } // FIXME: We should use this enum or something like it to get rid of the @@ -305,8 +339,8 @@ impl RealFileName { #[derive(Debug, Eq, PartialEq, Clone, Ord, PartialOrd, Hash, Decodable, Encodable)] pub enum FileName { Real(RealFileName), - /// Call to `quote!`. - QuoteExpansion(Hash64), + /// Strings provided as `--cfg [cfgspec]`. + CfgSpec(Hash64), /// Command line. Anon(Hash64), /// Hack in `src/librustc_ast/parse.rs`. @@ -353,7 +387,7 @@ impl fmt::Display for FileNameDisplay<'_> { Real(ref name) => { write!(fmt, "{}", name.to_string_lossy(self.display_pref)) } - QuoteExpansion(_) => write!(fmt, "<quote expansion>"), + CfgSpec(_) => write!(fmt, "<cfgspec>"), MacroExpansion(_) => write!(fmt, "<macro expansion>"), Anon(_) => write!(fmt, "<anon>"), ProcMacroSourceCode(_) => write!(fmt, "<proc-macro source code>"), @@ -384,7 +418,7 @@ impl FileName { | ProcMacroSourceCode(_) | CliCrateAttr(_) | Custom(_) - | QuoteExpansion(_) + | CfgSpec(_) | DocTest(_, _) | InlineAsm(_) => false, } @@ -425,7 +459,7 @@ impl FileName { pub fn cfg_spec_source_code(src: &str) -> FileName { let mut hasher = StableHasher::new(); src.hash(&mut hasher); - FileName::QuoteExpansion(hasher.finish()) + FileName::CfgSpec(hasher.finish()) } pub fn cli_crate_attr_source_code(src: &str) -> FileName { @@ -872,8 +906,7 @@ impl Span { /// Check if you can select metavar spans for the given spans to get matching contexts. fn try_metavars(a: SpanData, b: SpanData, a_orig: Span, b_orig: Span) -> (SpanData, SpanData) { - let get = |mspans: &FxHashMap<_, _>, s| mspans.get(&s).copied(); - match with_metavar_spans(|mspans| (get(mspans, a_orig), get(mspans, b_orig))) { + match with_metavar_spans(|mspans| (mspans.get(a_orig), mspans.get(b_orig))) { (None, None) => {} (Some(meta_a), None) => { let meta_a = meta_a.data(); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b57b5df2609..f5ce5dbc9d6 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1287,6 +1287,7 @@ symbols! { mir_drop, mir_field, mir_goto, + mir_len, mir_make_place, mir_move, mir_offset, diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index 3a71592cbe0..92c1f6e7148 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -58,8 +58,10 @@ where // The AIX ABI expect byval for aggregates // See https://github.com/llvm/llvm-project/blob/main/clang/lib/CodeGen/Targets/PPC.cpp. + // The incoming parameter is represented as a pointer in the IR, + // the alignment is associated with the size of the register. (align 8 for 64bit) if !is_ret && abi == AIX { - arg.pass_by_stack_offset(None); + arg.pass_by_stack_offset(Some(Align::from_bytes(8).unwrap())); return; } diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs index e975102e238..d8b6ae8cf32 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnu.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs @@ -97,9 +97,9 @@ pub(crate) fn opts() -> TargetOptions { emit_debug_gdb_scripts: false, requires_uwtable: true, eh_frame_header: false, + debuginfo_kind: DebuginfoKind::Dwarf, // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to // output DWO, despite using DWARF, doesn't use ELF.. - debuginfo_kind: DebuginfoKind::Pdb, supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..Default::default() } diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index 4f370ec8bd0..86e52117dbf 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -44,9 +44,9 @@ pub(crate) fn opts() -> TargetOptions { has_thread_local: true, crt_static_allows_dylibs: true, crt_static_respected: true, + debuginfo_kind: DebuginfoKind::Dwarf, // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to // output DWO, despite using DWARF, doesn't use ELF.. - debuginfo_kind: DebuginfoKind::Pdb, supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]), ..Default::default() } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index b82bb27eb79..750d2756b4a 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -261,7 +261,6 @@ trait_selection_oc_fn_lang_correct_type = {$lang_item_name -> *[lang_item_name] lang item `{$lang_item_name}` } function has wrong type trait_selection_oc_fn_main_correct_type = `main` function has wrong type -trait_selection_oc_fn_start_correct_type = `#[start]` function has wrong type trait_selection_oc_generic = mismatched types trait_selection_oc_if_else_different = `if` and `else` have incompatible types @@ -396,7 +395,6 @@ trait_selection_subtype = ...so that the {$requirement -> [if_else_different] `if` and `else` have incompatible types [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] `#[start]` function has the correct type [fn_lang_correct_type] lang item function has the correct type [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type @@ -410,7 +408,6 @@ trait_selection_subtype_2 = ...so that {$requirement -> [if_else_different] `if` and `else` have incompatible types [no_else] `if` missing an `else` returns `()` [fn_main_correct_type] `main` function has the correct type - [fn_start_correct_type] `#[start]` function has the correct type [fn_lang_correct_type] lang item function has the correct type [intrinsic_correct_type] intrinsic has the correct type [method_correct_type] method receiver has the correct type diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9778299eb19..1e9ef5e536c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -2318,7 +2318,6 @@ impl<'tcx> ObligationCause<'tcx> { | ObligationCauseCode::MatchExpressionArm(_) | ObligationCauseCode::IfExpression { .. } | ObligationCauseCode::LetElse - | ObligationCauseCode::StartFunctionType | ObligationCauseCode::LangFunctionType(_) | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver => FailureCode::Error0308, @@ -2376,9 +2375,6 @@ impl<'tcx> ObligationCause<'tcx> { ObligationCauseCode::MainFunctionType => { ObligationCauseFailureCode::FnMainCorrectType { span } } - ObligationCauseCode::StartFunctionType => { - ObligationCauseFailureCode::FnStartCorrectType { span, subdiags } - } &ObligationCauseCode::LangFunctionType(lang_item_name) => { ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name } } @@ -2421,7 +2417,6 @@ impl<'tcx> ObligationCause<'tcx> { "const is compatible with trait" } ObligationCauseCode::MainFunctionType => "`main` function has the correct type", - ObligationCauseCode::StartFunctionType => "`#[start]` function has the correct type", ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type", ObligationCauseCode::IntrinsicType => "intrinsic has the correct type", ObligationCauseCode::MethodReceiver => "method receiver has the correct type", @@ -2442,7 +2437,6 @@ impl IntoDiagArg for ObligationCauseAsDiagArg<'_> { "const_compat" } ObligationCauseCode::MainFunctionType => "fn_main_correct_type", - ObligationCauseCode::StartFunctionType => "fn_start_correct_type", ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type", ObligationCauseCode::IntrinsicType => "intrinsic_correct_type", ObligationCauseCode::MethodReceiver => "method_correct_type", diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs index 3416a17624e..503090b5797 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs @@ -420,8 +420,8 @@ fn make_elided_region_spans_suggs<'a>( let mut process_consecutive_brackets = |span: Option<Span>, spans_suggs: &mut Vec<(Span, String)>| { - if span - .is_some_and(|span| bracket_span.map_or(true, |bracket_span| span == bracket_span)) + if let Some(span) = span + && bracket_span.is_none_or(|bracket_span| span == bracket_span) { consecutive_brackets += 1; } else if let Some(bracket_span) = bracket_span.take() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 36270e0da78..21124cf20e5 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -167,6 +167,18 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { exp_span, exp_found.expected, exp_found.found, ); + match self.tcx.coroutine_kind(cause.body_id) { + Some(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async | hir::CoroutineDesugaring::AsyncGen, + _, + )) => (), + None + | Some( + hir::CoroutineKind::Coroutine(_) + | hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _), + ) => return, + } + if let ObligationCauseCode::CompareImplItem { .. } = cause.code() { return; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index fc0de13aeab..b4d294a70c0 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -172,14 +172,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let bound_predicate = predicate.kind(); let mut err = match bound_predicate.skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => { - let trait_ref = bound_predicate.rebind(data.trait_ref); - debug!(?trait_ref); + let trait_pred = bound_predicate.rebind(data); + debug!(?trait_pred); if let Err(e) = predicate.error_reported() { return e; } - if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) { + if let Err(guar) = self.tcx.ensure().coherent_trait(trait_pred.def_id()) { // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. return guar; @@ -200,13 +200,13 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. - if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) { + if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Sized) { match self.tainted_by_errors() { None => { let err = self.emit_inference_failure_err( obligation.cause.body_id, span, - trait_ref.self_ty().skip_binder().into(), + trait_pred.self_ty().skip_binder().into(), TypeAnnotationNeeded::E0282, false, ); @@ -251,10 +251,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut ambiguities = compute_applicable_impls_for_diagnostics( self.infcx, - &obligation.with(self.tcx, trait_ref), + &obligation.with(self.tcx, trait_pred), ); - let has_non_region_infer = - trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer()); + let has_non_region_infer = trait_pred + .skip_binder() + .trait_ref + .args + .types() + .any(|t| !t.is_ty_or_numeric_infer()); // It doesn't make sense to talk about applicable impls if there are more than a // handful of them. If there are a lot of them, but only a few of them have no type // params, we only show those, as they are more likely to be useful/intended. @@ -294,7 +298,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if impl_candidates.len() < 40 { self.report_similar_impl_candidates( impl_candidates.as_slice(), - trait_ref, + trait_pred, obligation.cause.body_id, &mut err, false, @@ -306,7 +310,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let ObligationCauseCode::WhereClause(def_id, _) | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code() { - self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); + self.suggest_fully_qualified_path(&mut err, def_id, span, trait_pred.def_id()); } if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack()) diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 6076c999086..bcd3b0109b7 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -23,9 +23,7 @@ use rustc_middle::ty::print::{ FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, PrintTraitRefExt as _, with_forced_trimmed_paths, }; -use rustc_middle::ty::{ - self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast, -}; +use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::{BytePos, DUMMY_SP, STDLIB_STABLE_CRATES, Span, Symbol, sym}; use tracing::{debug, instrument}; @@ -155,12 +153,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (leaf_trait_predicate, &obligation) }; - let main_trait_ref = main_trait_predicate.to_poly_trait_ref(); - let leaf_trait_ref = leaf_trait_predicate.to_poly_trait_ref(); - if let Some(guar) = self.emit_specialized_closure_kind_error( &obligation, - leaf_trait_ref, + leaf_trait_predicate, ) { return guar; } @@ -202,14 +197,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } = self.on_unimplemented_note(main_trait_predicate, main_obligation, &mut long_ty_file); let have_alt_message = message.is_some() || label.is_some(); - let is_try_conversion = self.is_try_conversion(span, main_trait_ref.def_id()); + let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id()); let is_unsize = - self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Unsize); + self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize); let (message, notes, append_const_msg) = if is_try_conversion { ( Some(format!( "`?` couldn't convert the error to `{}`", - main_trait_ref.skip_binder().self_ty(), + main_trait_predicate.skip_binder().self_ty(), )), vec![ "the question mark operation (`?`) implicitly performs a \ @@ -230,12 +225,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { post_message, ); - let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_ref.def_id(), LangItem::TransmuteTrait) + let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait) { // Recompute the safe transmute reason and use that for the error reporting match self.get_safe_transmute_error_and_reason( obligation.clone(), - main_trait_ref, + main_trait_predicate, span, ) { GetSafeTransmuteErrorAndReason::Silent => { @@ -266,7 +261,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let mut suggested = false; if is_try_conversion { - suggested = self.try_conversion_context(&obligation, main_trait_ref.skip_binder(), &mut err); + suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err); } if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) { @@ -274,12 +269,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ret_span, format!( "expected `{}` because of this", - main_trait_ref.skip_binder().self_ty() + main_trait_predicate.skip_binder().self_ty() ), ); } - if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Tuple) { + if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) { self.add_tuple_trait_message( obligation.cause.code().peel_derives(), &mut err, @@ -319,7 +314,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! err.span_label(span, s); - if !matches!(leaf_trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { + if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) { // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point // at the type param with a label to suggest constraining it. @@ -339,7 +334,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let ObligationCauseCode::Coercion { source, target } = *obligation.cause.code().peel_derives() { - if self.tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Sized) { + if self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Sized) { self.suggest_borrowing_for_object_cast( &mut err, root_obligation, @@ -368,7 +363,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.span_label(tcx.def_span(body), s); } - self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_ref); + self.suggest_floating_point_literal(&obligation, &mut err, leaf_trait_predicate); self.suggest_dereferencing_index(&obligation, &mut err, leaf_trait_predicate); suggested |= self.suggest_dereferences(&obligation, &mut err, leaf_trait_predicate); suggested |= self.suggest_fn_call(&obligation, &mut err, leaf_trait_predicate); @@ -376,7 +371,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { suggested = if let &[cand] = &impl_candidates[..] { let cand = cand.trait_ref; if let (ty::FnPtr(..), ty::FnDef(..)) = - (cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind()) + (cand.self_ty().kind(), main_trait_predicate.self_ty().skip_binder().kind()) { // Wrap method receivers and `&`-references in parens let suggestion = if self.tcx.sess.source_map().span_look_ahead(span, ".", Some(50)).is_some() { @@ -423,11 +418,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, leaf_trait_predicate, ); - self.note_version_mismatch(&mut err, leaf_trait_ref); + self.note_version_mismatch(&mut err, leaf_trait_predicate); self.suggest_remove_await(&obligation, &mut err); self.suggest_derive(&obligation, &mut err, leaf_trait_predicate); - if tcx.is_lang_item(leaf_trait_ref.def_id(), LangItem::Try) { + if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Try) { self.suggest_await_before_try( &mut err, &obligation, @@ -455,9 +450,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - let is_fn_trait = tcx.is_fn_trait(leaf_trait_ref.def_id()); + let is_fn_trait = tcx.is_fn_trait(leaf_trait_predicate.def_id()); let is_target_feature_fn = if let ty::FnDef(def_id, _) = - *leaf_trait_ref.skip_binder().self_ty().kind() + *leaf_trait_predicate.skip_binder().self_ty().kind() { !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() } else { @@ -509,7 +504,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } self.explain_hrtb_projection(&mut err, leaf_trait_predicate, obligation.param_env, &obligation.cause); - self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_ref); + self.suggest_desugaring_async_fn_in_trait(&mut err, main_trait_predicate); // Return early if the trait is Debug or Display and the invocation // originates within a standard library macro, because the output @@ -527,7 +522,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if in_std_macro && matches!( - self.tcx.get_diagnostic_name(leaf_trait_ref.def_id()), + self.tcx.get_diagnostic_name(leaf_trait_predicate.def_id()), Some(sym::Debug | sym::Display) ) { @@ -785,21 +780,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn emit_specialized_closure_kind_error( &self, obligation: &PredicateObligation<'tcx>, - mut trait_ref: ty::PolyTraitRef<'tcx>, + mut trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Option<ErrorGuaranteed> { // If `AsyncFnKindHelper` is not implemented, that means that the closure kind // doesn't extend the goal kind. This is worth reporting, but we can only do so // if we actually know which closure this goal comes from, so look at the cause // to see if we can extract that information. - if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::AsyncFnKindHelper) - && let Some(found_kind) = trait_ref.skip_binder().args.type_at(0).to_opt_closure_kind() + if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper) + && let Some(found_kind) = + trait_pred.skip_binder().trait_ref.args.type_at(0).to_opt_closure_kind() && let Some(expected_kind) = - trait_ref.skip_binder().args.type_at(1).to_opt_closure_kind() + trait_pred.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind() && !found_kind.extends(expected_kind) { if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() { // If we have a derived obligation, then the parent will be a `AsyncFn*` goal. - trait_ref = parent.to_poly_trait_ref(); + trait_pred = parent; } else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code() && let Some(typeck_results) = &self.typeck_results @@ -820,9 +816,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - let self_ty = trait_ref.self_ty().skip_binder(); + let self_ty = trait_pred.self_ty().skip_binder(); - if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id()) { + if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) { let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() { ty::Closure(def_id, args) => { (def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None) @@ -837,7 +833,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => return None, }; - let expected_args = trait_ref.map_bound(|trait_ref| trait_ref.args.type_at(1)); + let expected_args = + trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1)); // Verify that the arguments are compatible. If the signature is // mismatched, then we have a totally different error to report. @@ -909,7 +906,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn try_conversion_context( &self, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::TraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, err: &mut Diag<'_>, ) -> bool { let span = obligation.cause.span; @@ -953,8 +950,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) { return false; } - let self_ty = trait_ref.self_ty(); - let found_ty = trait_ref.args.get(1).and_then(|a| a.as_type()); + let self_ty = trait_pred.skip_binder().self_ty(); + let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type()); let mut prev_ty = self.resolve_vars_if_possible( typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)), @@ -1223,18 +1220,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { goal: ty::TraitPredicate<'tcx>, assumption: ty::PolyTraitPredicate<'tcx>, ) -> bool { + // Fast path if goal.polarity != assumption.polarity() { return false; } - let trait_goal = goal.trait_ref; let trait_assumption = self.instantiate_binder_with_fresh_vars( DUMMY_SP, infer::BoundRegionConversionTime::HigherRankedType, - assumption.to_poly_trait_ref(), + assumption, ); - self.can_eq(ty::ParamEnv::empty(), trait_goal, trait_assumption) + self.can_eq(ty::ParamEnv::empty(), goal.trait_ref, trait_assumption.trait_ref) } fn can_match_projection( @@ -1341,20 +1338,15 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let derive_better_type_error = |alias_term: ty::AliasTerm<'tcx>, expected_term: ty::Term<'tcx>| { let ocx = ObligationCtxt::new(self); - let normalized_term = match expected_term.unpack() { - ty::TermKind::Ty(_) => self.next_ty_var(DUMMY_SP).into(), - ty::TermKind::Const(_) => self.next_const_var(DUMMY_SP).into(), - }; - ocx.register_obligation(Obligation::new( - self.tcx, - ObligationCause::dummy(), + + let Ok(normalized_term) = ocx.structurally_normalize_term( + &ObligationCause::dummy(), obligation.param_env, - ty::PredicateKind::NormalizesTo(ty::NormalizesTo { - alias: alias_term, - term: normalized_term, - }), - )); - let _ = ocx.select_where_possible(); + alias_term.to_term(self.tcx), + ) else { + return None; + }; + if let Err(terr) = ocx.eq( &ObligationCause::dummy(), obligation.param_env, @@ -1682,7 +1674,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn report_similar_impl_candidates( &self, impl_candidates: &[ImplCandidate<'tcx>], - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, body_def_id: LocalDefId, err: &mut Diag<'_>, other: bool, @@ -1727,7 +1719,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // We'll check for the case where the reason for the mismatch is that the trait comes from // one crate version and the type comes from another crate version, even though they both // are from the same crate. - let trait_def_id = trait_ref.def_id(); + let trait_def_id = trait_pred.def_id(); let trait_name = self.tcx.item_name(trait_def_id); let crate_name = self.tcx.crate_name(trait_def_id.krate); if let Some(other_trait_def_id) = self.tcx.all_traits().find(|def_id| { @@ -1739,7 +1731,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // different crate `DefId`. We highlight the traits. let found_type = - if let ty::Adt(def, _) = trait_ref.self_ty().skip_binder().peel_refs().kind() { + if let ty::Adt(def, _) = trait_pred.self_ty().skip_binder().peel_refs().kind() { Some(def.did()) } else { None @@ -1836,7 +1828,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if self.probe(|_| { let ocx = ObligationCtxt::new(self); - self.enter_forall(trait_ref, |obligation_trait_ref| { + self.enter_forall(trait_pred, |obligation_trait_ref| { let impl_args = self.fresh_args_for_item(DUMMY_SP, single.impl_def_id); let impl_trait_ref = ocx.normalize( &ObligationCause::dummy(), @@ -1864,7 +1856,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let mut terrs = vec![]; for (obligation_arg, impl_arg) in - std::iter::zip(obligation_trait_ref.args, impl_trait_ref.args) + std::iter::zip(obligation_trait_ref.trait_ref.args, impl_trait_ref.args) { if (obligation_arg, impl_arg).references_error() { return false; @@ -1906,8 +1898,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let traits = self.cmp_traits( - obligation_trait_ref.def_id, - &obligation_trait_ref.args[1..], + obligation_trait_ref.def_id(), + &obligation_trait_ref.trait_ref.args[1..], impl_trait_ref.def_id, &impl_trait_ref.args[1..], ); @@ -1991,7 +1983,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } if let &[cand] = &candidates[..] { let (desc, mention_castable) = - match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) { + match (cand.self_ty().kind(), trait_pred.self_ty().skip_binder().kind()) { (ty::FnPtr(..), ty::FnDef(..)) => { (" implemented for fn pointer `", ", cast using `as`") } @@ -2055,7 +2047,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .filter(|cand| !self.tcx.do_not_recommend_impl(cand.impl_def_id)) .collect::<Vec<_>>(); - let def_id = trait_ref.def_id(); + let def_id = trait_pred.def_id(); if impl_candidates.is_empty() { if self.tcx.trait_is_auto(def_id) || self.tcx.lang_items().iter().any(|(_, id)| id == def_id) @@ -2132,11 +2124,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && !self.tcx.trait_is_auto(def_id) && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id) { - let trait_ref = trait_pred.to_poly_trait_ref(); let impl_candidates = self.find_similar_impl_candidates(trait_pred); self.report_similar_impl_candidates( &impl_candidates, - trait_ref, + trait_pred, body_def_id, err, true, @@ -2173,12 +2164,16 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// If the `Self` type of the unsatisfied trait `trait_ref` implements a trait /// with the same path as `trait_ref`, a help message about /// a probable version mismatch is added to `err` - fn note_version_mismatch(&self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>) -> bool { + fn note_version_mismatch( + &self, + err: &mut Diag<'_>, + trait_pred: ty::PolyTraitPredicate<'tcx>, + ) -> bool { let get_trait_impls = |trait_def_id| { let mut trait_impls = vec![]; self.tcx.for_each_relevant_impl( trait_def_id, - trait_ref.skip_binder().self_ty(), + trait_pred.skip_binder().self_ty(), |impl_def_id| { trait_impls.push(impl_def_id); }, @@ -2186,11 +2181,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_impls }; - let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); + let required_trait_path = self.tcx.def_path_str(trait_pred.def_id()); let traits_with_same_path: UnordSet<_> = self .tcx .visible_traits() - .filter(|trait_def_id| *trait_def_id != trait_ref.def_id()) + .filter(|trait_def_id| *trait_def_id != trait_pred.def_id()) .map(|trait_def_id| (self.tcx.def_path_str(trait_def_id), trait_def_id)) .filter(|(p, _)| *p == required_trait_path) .collect(); @@ -2374,7 +2369,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn get_safe_transmute_error_and_reason( &self, obligation: PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, span: Span, ) -> GetSafeTransmuteErrorAndReason { use rustc_transmute::Answer; @@ -2386,19 +2381,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Erase regions because layout code doesn't particularly care about regions. - let trait_ref = - self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref)); + let trait_pred = + self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_pred)); let src_and_dst = rustc_transmute::Types { - dst: trait_ref.args.type_at(0), - src: trait_ref.args.type_at(1), + dst: trait_pred.trait_ref.args.type_at(0), + src: trait_pred.trait_ref.args.type_at(1), }; let ocx = ObligationCtxt::new(self); let Ok(assume) = ocx.structurally_normalize_const( &obligation.cause, obligation.param_env, - trait_ref.args.const_at(2), + trait_pred.trait_ref.args.const_at(2), ) else { self.dcx().span_delayed_bug( span, @@ -2417,8 +2412,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return GetSafeTransmuteErrorAndReason::Silent; }; - let dst = trait_ref.args.type_at(0); - let src = trait_ref.args.type_at(1); + let dst = trait_pred.trait_ref.args.type_at(0); + let src = trait_pred.trait_ref.args.type_at(1); let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`"); match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable( @@ -2566,12 +2561,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_predicate.skip_binder().polarity, ) { - self.add_help_message_for_fn_trait( - trait_predicate.to_poly_trait_ref(), - err, - implemented_kind, - params, - ); + self.add_help_message_for_fn_trait(trait_predicate, err, implemented_kind, params); } else if !trait_predicate.has_non_region_infer() && self.predicate_can_apply(obligation.param_env, trait_predicate) { @@ -2606,7 +2596,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let impl_candidates = self.find_similar_impl_candidates(trait_predicate); if !self.report_similar_impl_candidates( &impl_candidates, - trait_predicate.to_poly_trait_ref(), + trait_predicate, body_def_id, err, true, @@ -2623,7 +2613,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.suggest_convert_to_slice( err, obligation, - trait_predicate.to_poly_trait_ref(), + trait_predicate, impl_candidates.as_slice(), span, ); @@ -2634,7 +2624,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn add_help_message_for_fn_trait( &self, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, err: &mut Diag<'_>, implemented_kind: ty::ClosureKind, params: ty::Binder<'tcx, Ty<'tcx>>, @@ -2647,12 +2637,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // to implement. let selected_kind = self .tcx - .fn_trait_kind_from_def_id(trait_ref.def_id()) + .fn_trait_kind_from_def_id(trait_pred.def_id()) .expect("expected to map DefId to ClosureKind"); if !implemented_kind.extends(selected_kind) { err.note(format!( "`{}` implements `{}`, but it must implement `{}`, which is more general", - trait_ref.skip_binder().self_ty(), + trait_pred.skip_binder().self_ty(), implemented_kind, selected_kind )); @@ -2660,7 +2650,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Note any argument mismatches let given_ty = params.skip_binder(); - let expected_ty = trait_ref.skip_binder().args.type_at(1); + let expected_ty = trait_pred.skip_binder().trait_ref.args.type_at(1); if let ty::Tuple(given) = given_ty.kind() && let ty::Tuple(expected) = expected_ty.kind() { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index cd4f77bb4cf..f2bcc51e687 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -433,33 +433,19 @@ pub fn report_dyn_incompatibility<'tcx>( hir::Node::Item(item) => Some(item.ident.span), _ => None, }); + let mut err = struct_span_code_err!( tcx.dcx(), span, E0038, - "the trait `{}` cannot be made into an object", + "the {} `{}` is not dyn compatible", + tcx.def_descr(trait_def_id), trait_str ); - err.span_label(span, format!("`{trait_str}` cannot be made into an object")); - - if let Some(hir_id) = hir_id - && let hir::Node::Ty(ty) = tcx.hir_node(hir_id) - && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind - { - let mut hir_id = hir_id; - while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) { - hir_id = ty.hir_id; - } - if tcx.parent_hir_node(hir_id).fn_sig().is_some() { - // Do not suggest `impl Trait` when dealing with things like super-traits. - err.span_suggestion_verbose( - ty.span.until(trait_ref.span), - "consider using an opaque type instead", - "impl ", - Applicability::MaybeIncorrect, - ); - } - } + err.span_label(span, format!("`{trait_str}` is not dyn compatible")); + + attempt_dyn_to_impl_suggestion(tcx, hir_id, &mut err); + let mut reported_violations = FxIndexSet::default(); let mut multi_span = vec![]; let mut messages = vec![]; @@ -474,7 +460,7 @@ pub fn report_dyn_incompatibility<'tcx>( if reported_violations.insert(violation.clone()) { let spans = violation.spans(); let msg = if trait_span.is_none() || spans.is_empty() { - format!("the trait cannot be made into an object because {}", violation.error_msg()) + format!("the trait is not dyn compatible because {}", violation.error_msg()) } else { format!("...because {}", violation.error_msg()) }; @@ -491,7 +477,7 @@ pub fn report_dyn_incompatibility<'tcx>( let has_multi_span = !multi_span.is_empty(); let mut note_span = MultiSpan::from_spans(multi_span.clone()); if let (Some(trait_span), true) = (trait_span, has_multi_span) { - note_span.push_span_label(trait_span, "this trait cannot be made into an object..."); + note_span.push_span_label(trait_span, "this trait is not dyn compatible..."); } for (span, msg) in iter::zip(multi_span, messages) { note_span.push_span_label(span, msg); @@ -499,16 +485,12 @@ pub fn report_dyn_incompatibility<'tcx>( // FIXME(dyn_compat_renaming): Update the URL. err.span_note( note_span, - "for a trait to be \"dyn-compatible\" 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>", + "for a trait to be dyn compatible it needs to allow building a vtable\n\ + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>", ); // Only provide the help if its a local trait, otherwise it's not actionable. if trait_span.is_some() { - let mut reported_violations: Vec<_> = reported_violations.into_iter().collect(); - reported_violations.sort(); - let mut potential_solutions: Vec<_> = reported_violations.into_iter().map(|violation| violation.solution()).collect(); potential_solutions.sort(); @@ -519,68 +501,116 @@ pub fn report_dyn_incompatibility<'tcx>( } } + attempt_dyn_to_enum_suggestion(tcx, trait_def_id, &*trait_str, &mut err); + + err +} + +/// Attempt to suggest converting the `dyn Trait` argument to an enumeration +/// over the types that implement `Trait`. +fn attempt_dyn_to_enum_suggestion( + tcx: TyCtxt<'_>, + trait_def_id: DefId, + trait_str: &str, + err: &mut Diag<'_>, +) { let impls_of = tcx.trait_impls_of(trait_def_id); - let impls = if impls_of.blanket_impls().is_empty() { - impls_of - .non_blanket_impls() - .values() - .flatten() - .filter(|def_id| { - !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..)) - }) - .collect::<Vec<_>>() - } else { - vec![] - }; - let externally_visible = if !impls.is_empty() - && let Some(def_id) = trait_def_id.as_local() + + if !impls_of.blanket_impls().is_empty() { + return; + } + + let concrete_impls: Option<Vec<Ty<'_>>> = impls_of + .non_blanket_impls() + .values() + .flatten() + .map(|impl_id| { + // Don't suggest conversion to enum if the impl types have type parameters. + // It's unlikely the user wants to define a generic enum. + let Some(impl_type) = tcx.type_of(*impl_id).no_bound_vars() else { return None }; + + // Obviously unsized impl types won't be usable in an enum. + // Note: this doesn't use `Ty::is_trivially_sized` because that function + // defaults to assuming that things are *not* sized, whereas we want to + // fall back to assuming that things may be sized. + match impl_type.kind() { + ty::Str | ty::Slice(_) | ty::Dynamic(_, _, ty::DynKind::Dyn) => { + return None; + } + _ => {} + } + Some(impl_type) + }) + .collect(); + let Some(concrete_impls) = concrete_impls else { return }; + + const MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM: usize = 9; + if concrete_impls.is_empty() || concrete_impls.len() > MAX_IMPLS_TO_SUGGEST_CONVERTING_TO_ENUM { + return; + } + + let externally_visible = if let Some(def_id) = trait_def_id.as_local() { // We may be executing this during typeck, which would result in cycle // if we used effective_visibilities query, which looks into opaque types // (and therefore calls typeck). - && tcx.resolutions(()).effective_visibilities.is_exported(def_id) - { - true + tcx.resolutions(()).effective_visibilities.is_exported(def_id) } else { false }; - match &impls[..] { - [] => {} - _ if impls.len() > 9 => {} - [only] if externally_visible => { - err.help(with_no_trimmed_paths!(format!( - "only type `{}` is seen to implement the trait in this crate, consider using it \ - directly instead", - tcx.type_of(*only).instantiate_identity(), - ))); - } - [only] => { - err.help(with_no_trimmed_paths!(format!( - "only type `{}` implements the trait, consider using it directly instead", - tcx.type_of(*only).instantiate_identity(), - ))); - } - impls => { - let types = impls - .iter() - .map(|t| { - with_no_trimmed_paths!(format!(" {}", tcx.type_of(*t).instantiate_identity(),)) - }) - .collect::<Vec<_>>(); - err.help(format!( - "the following types implement the trait, consider defining an enum where each \ - variant holds one of these types, implementing `{}` for this new enum and using \ - it instead:\n{}", - trait_str, - types.join("\n"), - )); - } + + if let [only_impl] = &concrete_impls[..] { + let within = if externally_visible { " within this crate" } else { "" }; + err.help(with_no_trimmed_paths!(format!( + "only type `{only_impl}` implements `{trait_str}`{within}; \ + consider using it directly instead." + ))); + } else { + let types = concrete_impls + .iter() + .map(|t| with_no_trimmed_paths!(format!(" {}", t))) + .collect::<Vec<String>>() + .join("\n"); + + err.help(format!( + "the following types implement `{trait_str}`:\n\ + {types}\n\ + consider defining an enum where each variant holds one of these types,\n\ + implementing `{trait_str}` for this new enum and using it instead", + )); } + if externally_visible { err.note(format!( - "`{trait_str}` can be implemented in other crates; if you want to support your users \ + "`{trait_str}` may be implemented in other crates; if you want to support your users \ passing their own types here, you can't refer to a specific type", )); } +} - err +/// Attempt to suggest that a `dyn Trait` argument or return type be converted +/// to use `impl Trait`. +fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, err: &mut Diag<'_>) { + let Some(hir_id) = hir_id else { return }; + let hir::Node::Ty(ty) = tcx.hir_node(hir_id) else { return }; + let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind else { return }; + + // Only suggest converting `dyn` to `impl` if we're in a function signature. + // This ensures that we don't suggest converting e.g. + // `type Alias = Box<dyn DynIncompatibleTrait>;` to + // `type Alias = Box<impl DynIncompatibleTrait>;` + let Some((_id, first_non_type_parent_node)) = + tcx.hir().parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_))) + else { + return; + }; + if first_non_type_parent_node.fn_sig().is_none() { + return; + } + + err.span_suggestion_verbose( + ty.span.until(trait_ref.span), + "consider using an opaque type instead", + "impl ", + Applicability::MaybeIncorrect, + ); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 2d248d00066..2d932e36470 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -10,7 +10,7 @@ use rustc_hir::{AttrArgs, AttrKind, Attribute}; use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; -use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt}; use rustc_parse_format::{ParseMode, Parser, Piece, Position}; use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES; use rustc_span::{Span, Symbol, kw, sym}; @@ -42,18 +42,18 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn impl_similar_to( &self, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, obligation: &PredicateObligation<'tcx>, ) -> Option<(DefId, GenericArgsRef<'tcx>)> { let tcx = self.tcx; let param_env = obligation.param_env; - self.enter_forall(trait_ref, |trait_ref| { - let trait_self_ty = trait_ref.self_ty(); + self.enter_forall(trait_pred, |trait_pred| { + let trait_self_ty = trait_pred.self_ty(); let mut self_match_impls = vec![]; let mut fuzzy_match_impls = vec![]; - self.tcx.for_each_relevant_impl(trait_ref.def_id, trait_self_ty, |def_id| { + self.tcx.for_each_relevant_impl(trait_pred.def_id(), trait_self_ty, |def_id| { let impl_args = self.fresh_args_for_item(obligation.cause.span, def_id); let impl_trait_ref = tcx.impl_trait_ref(def_id).unwrap().instantiate(tcx, impl_args); @@ -64,7 +64,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { self_match_impls.push((def_id, impl_args)); if iter::zip( - trait_ref.args.types().skip(1), + trait_pred.trait_ref.args.types().skip(1), impl_trait_ref.args.types().skip(1), ) .all(|(u, v)| self.fuzzy_match_tys(u, v, false).is_some()) @@ -117,7 +117,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } let (def_id, args) = self - .impl_similar_to(trait_pred.to_poly_trait_ref(), obligation) + .impl_similar_to(trait_pred, obligation) .unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args)); let trait_pred = trait_pred.skip_binder(); diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index 9d85ca1dd4d..4669d286665 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -32,9 +32,9 @@ use rustc_middle::ty::print::{ with_forced_trimmed_paths, with_no_trimmed_paths, }; use rustc_middle::ty::{ - self, AdtKind, GenericArgs, InferTy, IsSuggestable, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable, - TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast, - suggest_arbitrary_trait_bound, suggest_constraining_type_param, + self, AdtKind, GenericArgs, InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitableExt, TypeckResults, Upcast, suggest_arbitrary_trait_bound, + suggest_constraining_type_param, }; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::LocalDefId; @@ -218,15 +218,15 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( (_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)), (None, Some((ident, []))) => ( ident.span.shrink_to_hi(), - format!(": {}", trait_pred.to_poly_trait_ref().print_trait_sugared()), + format!(": {}", trait_pred.print_modifiers_and_trait_path()), ), (_, Some((_, [.., bounds]))) => ( bounds.span().shrink_to_hi(), - format!(" + {}", trait_pred.to_poly_trait_ref().print_trait_sugared()), + format!(" + {}", trait_pred.print_modifiers_and_trait_path()), ), (Some(_), Some((_, []))) => ( hir_generics.span.shrink_to_hi(), - format!(": {}", trait_pred.to_poly_trait_ref().print_trait_sugared()), + format!(": {}", trait_pred.print_modifiers_and_trait_path()), ), }; @@ -2740,7 +2740,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { | ObligationCauseCode::IfExpression { .. } | ObligationCauseCode::IfExpressionWithNoElse | ObligationCauseCode::MainFunctionType - | ObligationCauseCode::StartFunctionType | ObligationCauseCode::LangFunctionType(_) | ObligationCauseCode::IntrinsicType | ObligationCauseCode::MethodReceiver @@ -3729,7 +3728,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) { let rhs_span = match obligation.cause.code() { ObligationCauseCode::BinOp { rhs_span: Some(span), rhs_is_lit, .. } if *rhs_is_lit => { @@ -3737,8 +3736,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } _ => return, }; - if let ty::Float(_) = trait_ref.skip_binder().self_ty().kind() - && let ty::Infer(InferTy::IntVar(_)) = trait_ref.skip_binder().args.type_at(1).kind() + if let ty::Float(_) = trait_pred.skip_binder().self_ty().kind() + && let ty::Infer(InferTy::IntVar(_)) = + trait_pred.skip_binder().trait_ref.args.type_at(1).kind() { err.span_suggestion_verbose( rhs_span.shrink_to_hi(), @@ -4448,7 +4448,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, candidate_impls: &[ImplCandidate<'tcx>], span: Span, ) { @@ -4464,7 +4464,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // 1. `[T; _]` (array of T) // 2. `&[T; _]` (reference to array of T) // 3. `&mut [T; _]` (mutable reference to array of T) - let (element_ty, mut mutability) = match *trait_ref.skip_binder().self_ty().kind() { + let (element_ty, mut mutability) = match *trait_pred.skip_binder().self_ty().kind() { ty::Array(element_ty, _) => (element_ty, None), ty::Ref(_, pointee_ty, mutability) => match *pointee_ty.kind() { @@ -4620,14 +4620,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { pub(super) fn suggest_desugaring_async_fn_in_trait( &self, err: &mut Diag<'_>, - trait_ref: ty::PolyTraitRef<'tcx>, + trait_pred: ty::PolyTraitPredicate<'tcx>, ) { // Don't suggest if RTN is active -- we should prefer a where-clause bound instead. if self.tcx.features().return_type_notation() { return; } - let trait_def_id = trait_ref.def_id(); + let trait_def_id = trait_pred.def_id(); // Only suggest specifying auto traits if !self.tcx.trait_is_auto(trait_def_id) { @@ -4635,7 +4635,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Look for an RPITIT - let ty::Alias(ty::Projection, alias_ty) = trait_ref.self_ty().skip_binder().kind() else { + let ty::Alias(ty::Projection, alias_ty) = trait_pred.self_ty().skip_binder().kind() else { return; }; let Some(ty::ImplTraitInTraitData::Trait { fn_def_id, opaque_def_id }) = diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index 53a4e5031c6..0bf91ad35c1 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1695,13 +1695,6 @@ pub enum ObligationCauseFailureCode { #[primary_span] span: Span, }, - #[diag(trait_selection_oc_fn_start_correct_type, code = E0308)] - FnStartCorrectType { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, #[diag(trait_selection_oc_fn_lang_correct_type, code = E0308)] FnLangCorrectType { #[primary_span] diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs index 4498beff4ea..2b7da4bc5ff 100644 --- a/compiler/rustc_trait_selection/src/solve/fulfill.rs +++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs @@ -513,8 +513,27 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { _ => ChildMode::PassThrough, }; + let nested_goals = candidate.instantiate_nested_goals(self.span()); + + // If the candidate requires some `T: FnPtr` bound which does not hold should not be treated as + // an actual candidate, instead we should treat them as if the impl was never considered to + // have potentially applied. As if `impl<A, R> Trait for for<..> fn(..A) -> R` was written + // instead of `impl<T: FnPtr> Trait for T`. + // + // We do this as a separate loop so that we do not choose to tell the user about some nested + // goal before we encounter a `T: FnPtr` nested goal. + for nested_goal in &nested_goals { + if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait() + && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause() + && poly_trait_pred.def_id() == fn_ptr_trait + && let Err(NoSolution) = nested_goal.result() + { + return ControlFlow::Break(self.obligation.clone()); + } + } + let mut impl_where_bound_count = 0; - for nested_goal in candidate.instantiate_nested_goals(self.span()) { + for nested_goal in nested_goals { trace!(nested_goal = ?(nested_goal.goal(), nested_goal.source(), nested_goal.result())); let make_obligation = |cause| Obligation { @@ -605,7 +624,7 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> { } } -#[derive(Copy, Clone)] +#[derive(Debug, Copy, Clone)] enum ChildMode<'tcx> { // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`, // and skip all `GoalSource::Misc`, which represent useless obligations diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index e27143f1396..50d47d20e1a 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -709,7 +709,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { if matches!(ty.kind(), ty::Alias(..)) { let ocx = ObligationCtxt::new(infcx); ty = ocx - .structurally_normalize(&ObligationCause::dummy(), param_env, ty) + .structurally_normalize_ty(&ObligationCause::dummy(), param_env, ty) .map_err(|_| ())?; if !ocx.select_where_possible().is_empty() { return Err(()); diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs index d2abd881c45..66491d9abe1 100644 --- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs +++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::{ TypeVisitableExt, TypeVisitor, TypingMode, Upcast, }; use rustc_span::Span; +use rustc_type_ir::elaborate; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -39,7 +40,7 @@ pub fn hir_ty_lowering_dyn_compatibility_violations( trait_def_id: DefId, ) -> Vec<DynCompatibilityViolation> { debug_assert!(tcx.generics_of(trait_def_id).has_self); - tcx.supertrait_def_ids(trait_def_id) + elaborate::supertrait_def_ids(tcx, trait_def_id) .map(|def_id| predicates_reference_self(tcx, def_id, true)) .filter(|spans| !spans.is_empty()) .map(DynCompatibilityViolation::SupertraitSelf) @@ -52,9 +53,8 @@ fn dyn_compatibility_violations( ) -> &'_ [DynCompatibilityViolation] { debug_assert!(tcx.generics_of(trait_def_id).has_self); debug!("dyn_compatibility_violations: {:?}", trait_def_id); - tcx.arena.alloc_from_iter( - tcx.supertrait_def_ids(trait_def_id) + elaborate::supertrait_def_ids(tcx, trait_def_id) .flat_map(|def_id| dyn_compatibility_violations_for_trait(tcx, def_id)), ) } diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 5e270b62b00..4a3983fca31 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -319,7 +319,7 @@ where self.infcx.at(cause, param_env).deeply_normalize(value, &mut **self.engine.borrow_mut()) } - pub fn structurally_normalize( + pub fn structurally_normalize_ty( &self, cause: &ObligationCause<'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -327,7 +327,7 @@ where ) -> Result<Ty<'tcx>, Vec<E>> { self.infcx .at(cause, param_env) - .structurally_normalize(value, &mut **self.engine.borrow_mut()) + .structurally_normalize_ty(value, &mut **self.engine.borrow_mut()) } pub fn structurally_normalize_const( @@ -340,4 +340,15 @@ where .at(cause, param_env) .structurally_normalize_const(value, &mut **self.engine.borrow_mut()) } + + pub fn structurally_normalize_term( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: ty::Term<'tcx>, + ) -> Result<ty::Term<'tcx>, Vec<E>> { + self.infcx + .at(cause, param_env) + .structurally_normalize_term(value, &mut **self.engine.borrow_mut()) + } } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index da16a742099..fe5ad003a7e 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -66,9 +66,9 @@ pub use self::specialize::{ }; pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::{ - BoundVarReplacer, PlaceholderReplacer, TraitAliasExpander, TraitAliasExpansionInfo, elaborate, - expand_trait_aliases, impl_item_is_final, supertraits, - transitive_bounds_that_define_assoc_item, upcast_choices, with_replaced_escaping_bound_vars, + BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final, + supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices, + with_replaced_escaping_bound_vars, }; use crate::error_reporting::InferCtxtErrorExt; use crate::infer::outlives::env::OutlivesEnvironment; diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index d59cf88875e..537b042bde5 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -18,6 +18,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, Term, Ty, TyCtxt, TypingMode, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::sym; +use rustc_type_ir::elaborate; use thin_vec::thin_vec; use tracing::{debug, instrument}; @@ -836,8 +837,7 @@ fn assemble_candidates_from_object_ty<'cx, 'tcx>( if tcx.is_impl_trait_in_trait(obligation.predicate.def_id) && let Some(out_trait_def_id) = data.principal_def_id() && let rpitit_trait_def_id = tcx.parent(obligation.predicate.def_id) - && tcx - .supertrait_def_ids(out_trait_def_id) + && elaborate::supertrait_def_ids(tcx, out_trait_def_id) .any(|trait_def_id| trait_def_id == rpitit_trait_def_id) { candidate_set.push_candidate(ProjectionCandidate::ObjectRpitit); 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 968dc631e50..13a6744c2e9 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -16,9 +16,9 @@ use rustc_infer::traits::{ Obligation, ObligationCause, PolyTraitObligation, PredicateObligations, SelectionError, }; use rustc_middle::ty::fast_reject::DeepRejectCtxt; -use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt, TypingMode}; +use rustc_middle::ty::{self, Ty, TypeVisitableExt, TypingMode}; use rustc_middle::{bug, span_bug}; -use rustc_type_ir::Interner; +use rustc_type_ir::{Interner, elaborate}; use tracing::{debug, instrument, trace}; use super::SelectionCandidate::*; @@ -186,10 +186,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } selcx.infcx.probe(|_| { + // We checked the polarity already match selcx.match_normalize_trait_ref( obligation, placeholder_trait_predicate.trait_ref, - bound.to_poly_trait_ref(), + bound.map_bound(|pred| pred.trait_ref), ) { Ok(None) => { candidates.vec.push(ProjectionCandidate(idx)); @@ -1002,8 +1003,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let a_auto_traits: FxIndexSet<DefId> = a_data .auto_traits() .chain(principal_def_id_a.into_iter().flat_map(|principal_def_id| { - self.tcx() - .supertrait_def_ids(principal_def_id) + elaborate::supertrait_def_ids(self.tcx(), principal_def_id) .filter(|def_id| self.tcx().trait_is_auto(*def_id)) })) .collect(); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0ccb0fc0615..729ae3f2c2a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -16,7 +16,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::{DefineOpaqueTypes, HigherRankedType, InferOk}; use rustc_infer::traits::ObligationCauseCode; use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData}; -use rustc_middle::ty::{self, GenericArgsRef, ToPolyTraitRef, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast}; use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_type_ir::elaborate; @@ -458,8 +458,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ensure_sufficient_stack(|| { let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived); - let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); - let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref); + assert_eq!(obligation.predicate.polarity(), ty::PredicatePolarity::Positive); + let trait_ref = + self.infcx.enter_forall_and_leak_universe(obligation.predicate).trait_ref; let trait_obligations = self.impl_or_trait_obligations( &cause, obligation.recursion_depth + 1, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 5581ea46882..0cc0d7f786b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -32,6 +32,7 @@ use rustc_middle::ty::{ TypingMode, Upcast, }; use rustc_span::{Symbol, sym}; +use rustc_type_ir::elaborate; use tracing::{debug, instrument, trace}; use self::EvaluationResult::*; @@ -2531,7 +2532,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let a_auto_traits: FxIndexSet<DefId> = a_data .auto_traits() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { - tcx.supertrait_def_ids(principal_def_id).filter(|def_id| tcx.trait_is_auto(*def_id)) + elaborate::supertrait_def_ids(tcx, principal_def_id) + .filter(|def_id| tcx.trait_is_auto(*def_id)) })) .collect(); diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs index f8e8f2176c1..e6d5d336b8d 100644 --- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -7,44 +7,12 @@ use crate::traits::{NormalizeExt, Obligation}; #[extension(pub trait StructurallyNormalizeExt<'tcx>)] impl<'tcx> At<'_, 'tcx> { - fn structurally_normalize<E: 'tcx>( + fn structurally_normalize_ty<E: 'tcx>( &self, ty: Ty<'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() { - let ty::Alias(..) = *ty.kind() else { - return Ok(ty); - }; - - let new_infer_ty = self.infcx.next_ty_var(self.cause.span); - - // We simply emit an `alias-eq` goal here, since that will take care of - // normalizing the LHS of the projection until it is a rigid projection - // (or a not-yet-defined opaque in scope). - let obligation = Obligation::new( - self.infcx.tcx, - self.cause.clone(), - self.param_env, - ty::PredicateKind::AliasRelate( - ty.into(), - new_infer_ty.into(), - ty::AliasRelationDirection::Equate, - ), - ); - - fulfill_cx.register_predicate_obligation(self.infcx, obligation); - let errors = fulfill_cx.select_where_possible(self.infcx); - if !errors.is_empty() { - return Err(errors); - } - - Ok(self.infcx.resolve_vars_if_possible(new_infer_ty)) - } else { - Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx)) - } + self.structurally_normalize_term(ty.into(), fulfill_cx).map(|term| term.expect_type()) } fn structurally_normalize_const<E: 'tcx>( @@ -52,14 +20,29 @@ impl<'tcx> At<'_, 'tcx> { ct: ty::Const<'tcx>, fulfill_cx: &mut dyn TraitEngine<'tcx, E>, ) -> Result<ty::Const<'tcx>, Vec<E>> { - assert!(!ct.is_ct_infer(), "should have resolved vars before calling"); + if self.infcx.tcx.features().generic_const_exprs() { + return Ok(super::evaluate_const(&self.infcx, ct, self.param_env)); + } + + self.structurally_normalize_term(ct.into(), fulfill_cx).map(|term| term.expect_const()) + } + + fn structurally_normalize_term<E: 'tcx>( + &self, + term: ty::Term<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx, E>, + ) -> Result<ty::Term<'tcx>, Vec<E>> { + assert!(!term.is_infer(), "should have resolved vars before calling"); if self.infcx.next_trait_solver() { - let ty::ConstKind::Unevaluated(..) = ct.kind() else { - return Ok(ct); - }; + if let None = term.to_alias_term() { + return Ok(term); + } - let new_infer_ct = self.infcx.next_const_var(self.cause.span); + let new_infer = match term.unpack() { + ty::TermKind::Ty(_) => self.infcx.next_ty_var(self.cause.span).into(), + ty::TermKind::Const(_) => self.infcx.next_const_var(self.cause.span).into(), + }; // We simply emit an `alias-eq` goal here, since that will take care of // normalizing the LHS of the projection until it is a rigid projection @@ -68,11 +51,7 @@ impl<'tcx> At<'_, 'tcx> { self.infcx.tcx, self.cause.clone(), self.param_env, - ty::PredicateKind::AliasRelate( - ct.into(), - new_infer_ct.into(), - ty::AliasRelationDirection::Equate, - ), + ty::PredicateKind::AliasRelate(term, new_infer, ty::AliasRelationDirection::Equate), ); fulfill_cx.register_predicate_obligation(self.infcx, obligation); @@ -81,11 +60,9 @@ impl<'tcx> At<'_, 'tcx> { return Err(errors); } - Ok(self.infcx.resolve_vars_if_possible(new_infer_ct)) - } else if self.infcx.tcx.features().generic_const_exprs() { - Ok(super::evaluate_const(&self.infcx, ct, self.param_env)) + Ok(self.infcx.resolve_vars_if_possible(new_infer)) } else { - Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx)) + Ok(self.normalize(term).into_value_registering_obligations(self.infcx, fulfill_cx)) } } } diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index da1045b664a..c9fb2a757e1 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -1,162 +1,85 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, VecDeque}; -use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::Diag; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir::def_id::DefId; use rustc_infer::infer::InferCtxt; pub use rustc_infer::traits::util::*; use rustc_middle::bug; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, Upcast, + self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_span::Span; use smallvec::{SmallVec, smallvec}; use tracing::debug; -/////////////////////////////////////////////////////////////////////////// -// `TraitAliasExpander` iterator -/////////////////////////////////////////////////////////////////////////// - -/// "Trait alias expansion" is the process of expanding a sequence of trait -/// references into another sequence by transitively following all trait -/// aliases. e.g. If you have bounds like `Foo + Send`, a trait alias -/// `trait Foo = Bar + Sync;`, and another trait alias -/// `trait Bar = Read + Write`, then the bounds would expand to -/// `Read + Write + Sync + Send`. -/// Expansion is done via a DFS (depth-first search), and the `visited` field -/// is used to avoid cycles. -pub struct TraitAliasExpander<'tcx> { - tcx: TyCtxt<'tcx>, - stack: Vec<TraitAliasExpansionInfo<'tcx>>, -} - -/// Stores information about the expansion of a trait via a path of zero or more trait aliases. -#[derive(Debug, Clone)] -pub struct TraitAliasExpansionInfo<'tcx> { - pub path: SmallVec<[(ty::PolyTraitRef<'tcx>, Span); 4]>, -} - -impl<'tcx> TraitAliasExpansionInfo<'tcx> { - fn new(trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - Self { path: smallvec![(trait_ref, span)] } - } - - /// Adds diagnostic labels to `diag` for the expansion path of a trait through all intermediate - /// trait aliases. - pub fn label_with_exp_info( - &self, - diag: &mut Diag<'_>, - top_label: &'static str, - use_desc: &str, - ) { - diag.span_label(self.top().1, top_label); - if self.path.len() > 1 { - for (_, sp) in self.path.iter().rev().skip(1).take(self.path.len() - 2) { - diag.span_label(*sp, format!("referenced here ({use_desc})")); - } - } - if self.top().1 != self.bottom().1 { - // When the trait object is in a return type these two spans match, we don't want - // redundant labels. - diag.span_label( - self.bottom().1, - format!("trait alias used in trait object type ({use_desc})"), - ); - } - } - - pub fn trait_ref(&self) -> ty::PolyTraitRef<'tcx> { - self.top().0 - } - - pub fn top(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.last().unwrap() - } - - pub fn bottom(&self) -> &(ty::PolyTraitRef<'tcx>, Span) { - self.path.first().unwrap() - } - - fn clone_and_push(&self, trait_ref: ty::PolyTraitRef<'tcx>, span: Span) -> Self { - let mut path = self.path.clone(); - path.push((trait_ref, span)); - - Self { path } - } -} - +/// Return the trait and projection predicates that come from eagerly expanding the +/// trait aliases in the list of clauses. For each trait predicate, record a stack +/// of spans that trace from the user-written trait alias bound. For projection predicates, +/// just record the span of the projection itself. +/// +/// For trait aliases, we don't deduplicte the predicates, since we currently do not +/// consider duplicated traits as a single trait for the purposes of our "one trait principal" +/// restriction; however, for projections we do deduplicate them. +/// +/// ```rust,ignore (fails) +/// trait Bar {} +/// trait Foo = Bar + Bar; +/// +/// let not_object_safe: dyn Foo; // bad, two `Bar` principals. +/// ``` pub fn expand_trait_aliases<'tcx>( tcx: TyCtxt<'tcx>, - trait_refs: impl Iterator<Item = (ty::PolyTraitRef<'tcx>, Span)>, -) -> TraitAliasExpander<'tcx> { - let items: Vec<_> = - trait_refs.map(|(trait_ref, span)| TraitAliasExpansionInfo::new(trait_ref, span)).collect(); - TraitAliasExpander { tcx, stack: items } -} - -impl<'tcx> TraitAliasExpander<'tcx> { - /// If `item` is a trait alias and its predicate has not yet been visited, then expands `item` - /// to the definition, pushes the resulting expansion onto `self.stack`, and returns `false`. - /// Otherwise, immediately returns `true` if `item` is a regular trait, or `false` if it is a - /// trait alias. - /// The return value indicates whether `item` should be yielded to the user. - fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool { - let tcx = self.tcx; - let trait_ref = item.trait_ref(); - let pred = trait_ref.upcast(tcx); - - debug!("expand_trait_aliases: trait_ref={:?}", trait_ref); - - // Don't recurse if this bound is not a trait alias. - let is_alias = tcx.is_trait_alias(trait_ref.def_id()); - if !is_alias { - return true; - } - - // Don't recurse if this trait alias is already on the stack for the DFS search. - let anon_pred = anonymize_predicate(tcx, pred); - if item - .path - .iter() - .rev() - .skip(1) - .any(|&(tr, _)| anonymize_predicate(tcx, tr.upcast(tcx)) == anon_pred) - { - return false; - } - - // Get components of trait alias. - let predicates = tcx.explicit_super_predicates_of(trait_ref.def_id()); - debug!(?predicates); - - let items = predicates.skip_binder().iter().rev().filter_map(|(pred, span)| { - pred.instantiate_supertrait(tcx, trait_ref) - .as_trait_clause() - .map(|trait_ref| item.clone_and_push(trait_ref.map_bound(|t| t.trait_ref), *span)) - }); - debug!("expand_trait_aliases: items={:?}", items.clone().collect::<Vec<_>>()); - - self.stack.extend(items); - - false - } -} - -impl<'tcx> Iterator for TraitAliasExpander<'tcx> { - type Item = TraitAliasExpansionInfo<'tcx>; - - fn size_hint(&self) -> (usize, Option<usize>) { - (self.stack.len(), None) - } - - fn next(&mut self) -> Option<TraitAliasExpansionInfo<'tcx>> { - while let Some(item) = self.stack.pop() { - if self.expand(&item) { - return Some(item); + clauses: impl IntoIterator<Item = (ty::Clause<'tcx>, Span)>, +) -> ( + Vec<(ty::PolyTraitPredicate<'tcx>, SmallVec<[Span; 1]>)>, + Vec<(ty::PolyProjectionPredicate<'tcx>, Span)>, +) { + let mut trait_preds = vec![]; + let mut projection_preds = vec![]; + let mut seen_projection_preds = FxHashSet::default(); + + let mut queue: VecDeque<_> = clauses.into_iter().map(|(p, s)| (p, smallvec![s])).collect(); + + while let Some((clause, spans)) = queue.pop_front() { + match clause.kind().skip_binder() { + ty::ClauseKind::Trait(trait_pred) => { + if tcx.is_trait_alias(trait_pred.def_id()) { + queue.extend( + tcx.explicit_super_predicates_of(trait_pred.def_id()) + .iter_identity_copied() + .map(|(clause, span)| { + let mut spans = spans.clone(); + spans.push(span); + ( + clause.instantiate_supertrait( + tcx, + clause.kind().rebind(trait_pred.trait_ref), + ), + spans, + ) + }), + ); + } else { + trait_preds.push((clause.kind().rebind(trait_pred), spans)); + } } + ty::ClauseKind::Projection(projection_pred) => { + let projection_pred = clause.kind().rebind(projection_pred); + if !seen_projection_preds.insert(tcx.anonymize_bound_vars(projection_pred)) { + continue; + } + projection_preds.push((projection_pred, *spans.last().unwrap())); + } + ty::ClauseKind::RegionOutlives(..) + | ty::ClauseKind::TypeOutlives(..) + | ty::ClauseKind::ConstArgHasType(_, _) + | ty::ClauseKind::WellFormed(_) + | ty::ClauseKind::ConstEvaluatable(_) + | ty::ClauseKind::HostEffect(..) => {} } - None } + + (trait_preds, projection_preds) } /////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 71c3646498b..3213638afb2 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -47,6 +47,7 @@ use std::ops::ControlFlow; use rustc_ast_ir::visit::VisitorResult; use rustc_ast_ir::{try_visit, walk_visitable_list}; use rustc_index::{Idx, IndexVec}; +use smallvec::SmallVec; use thin_vec::ThinVec; use crate::data_structures::Lrc; @@ -192,6 +193,13 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for ThinVec<T> { } } +impl<I: Interner, T: TypeVisitable<I>, const N: usize> TypeVisitable<I> for SmallVec<[T; N]> { + fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result { + walk_visitable_list!(visitor, self.iter()); + V::Result::output() + } +} + // `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general // case, because we can't return a new slice. But note that there are a couple // of trivial impls of `TypeFoldable` for specific slice types elsewhere. diff --git a/library/Cargo.lock b/library/Cargo.lock index c8007dd9be0..7b9081d46a0 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -166,9 +166,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", "compiler_builtins", diff --git a/library/alloc/src/bstr.rs b/library/alloc/src/bstr.rs new file mode 100644 index 00000000000..61e61019b50 --- /dev/null +++ b/library/alloc/src/bstr.rs @@ -0,0 +1,702 @@ +//! The `ByteStr` and `ByteString` types and trait implementations. + +// This could be more fine-grained. +#![cfg(not(no_global_oom_handling))] + +use core::borrow::{Borrow, BorrowMut}; +#[unstable(feature = "bstr", issue = "134915")] +pub use core::bstr::ByteStr; +use core::bstr::{impl_partial_eq, impl_partial_eq_n, impl_partial_eq_ord}; +use core::cmp::Ordering; +use core::ops::{ + Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, + RangeTo, RangeToInclusive, +}; +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +use core::str::FromStr; +use core::{fmt, hash}; + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +use crate::borrow::{Cow, ToOwned}; +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +use crate::boxed::Box; +#[cfg(not(no_rc))] +use crate::rc::Rc; +use crate::string::String; +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] +use crate::sync::Arc; +use crate::vec::Vec; + +/// A wrapper for `Vec<u8>` representing a human-readable string that's conventionally, but not +/// always, UTF-8. +/// +/// Unlike `String`, this type permits non-UTF-8 contents, making it suitable for user input, +/// non-native filenames (as `Path` only supports native filenames), and other applications that +/// need to round-trip whatever data the user provides. +/// +/// A `ByteString` owns its contents and can grow and shrink, like a `Vec` or `String`. For a +/// borrowed byte string, see [`ByteStr`](../../std/bstr/struct.ByteStr.html). +/// +/// `ByteString` implements `Deref` to `&Vec<u8>`, so all methods available on `&Vec<u8>` are +/// available on `ByteString`. Similarly, `ByteString` implements `DerefMut` to `&mut Vec<u8>`, +/// so you can modify a `ByteString` using any method available on `&mut Vec<u8>`. +/// +/// The `Debug` and `Display` implementations for `ByteString` are the same as those for `ByteStr`, +/// showing invalid UTF-8 as hex escapes or the Unicode replacement character, respectively. +#[unstable(feature = "bstr", issue = "134915")] +#[repr(transparent)] +#[derive(Clone)] +#[doc(alias = "BString")] +pub struct ByteString(pub Vec<u8>); + +impl ByteString { + #[inline] + pub(crate) fn as_bytes(&self) -> &[u8] { + &self.0 + } + + #[inline] + pub(crate) fn as_bytestr(&self) -> &ByteStr { + ByteStr::new(&self.0) + } + + #[inline] + pub(crate) fn as_mut_bytestr(&mut self) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Deref for ByteString { + type Target = Vec<u8>; + + #[inline] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl DerefMut for ByteString { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for ByteString {} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Debug for ByteString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_bytestr(), f) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Display for ByteString { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_bytestr(), f) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<[u8]> for ByteString { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<ByteStr> for ByteString { + #[inline] + fn as_ref(&self) -> &ByteStr { + self.as_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsMut<[u8]> for ByteString { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsMut<ByteStr> for ByteString { + #[inline] + fn as_mut(&mut self) -> &mut ByteStr { + self.as_mut_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Borrow<[u8]> for ByteString { + #[inline] + fn borrow(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Borrow<ByteStr> for ByteString { + #[inline] + fn borrow(&self) -> &ByteStr { + self.as_bytestr() + } +} + +// `impl Borrow<ByteStr> for Vec<u8>` omitted to avoid inference failures +// `impl Borrow<ByteStr> for String` omitted to avoid inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl BorrowMut<[u8]> for ByteString { + #[inline] + fn borrow_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl BorrowMut<ByteStr> for ByteString { + #[inline] + fn borrow_mut(&mut self) -> &mut ByteStr { + self.as_mut_bytestr() + } +} + +// `impl BorrowMut<ByteStr> for Vec<u8>` omitted to avoid inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl Default for ByteString { + fn default() -> Self { + ByteString(Vec::new()) + } +} + +// Omitted due to inference failures +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a, const N: usize> From<&'a [u8; N]> for ByteString { +// #[inline] +// fn from(s: &'a [u8; N]) -> Self { +// ByteString(s.as_slice().to_vec()) +// } +// } +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<const N: usize> From<[u8; N]> for ByteString { +// #[inline] +// fn from(s: [u8; N]) -> Self { +// ByteString(s.as_slice().to_vec()) +// } +// } +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a [u8]> for ByteString { +// #[inline] +// fn from(s: &'a [u8]) -> Self { +// ByteString(s.to_vec()) +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl From<Vec<u8>> for ByteString { +// #[inline] +// fn from(s: Vec<u8>) -> Self { +// ByteString(s) +// } +// } + +#[unstable(feature = "bstr", issue = "134915")] +impl From<ByteString> for Vec<u8> { + #[inline] + fn from(s: ByteString) -> Self { + s.0 + } +} + +// Omitted due to inference failures +// +// #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a str> for ByteString { +// #[inline] +// fn from(s: &'a str) -> Self { +// ByteString(s.as_bytes().to_vec()) +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl From<String> for ByteString { +// #[inline] +// fn from(s: String) -> Self { +// ByteString(s.into_bytes()) +// } +// } + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a ByteStr> for ByteString { + #[inline] + fn from(s: &'a ByteStr) -> Self { + ByteString(s.0.to_vec()) + } +} + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<ByteString> for Cow<'a, ByteStr> { + #[inline] + fn from(s: ByteString) -> Self { + Cow::Owned(s) + } +} + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a ByteString> for Cow<'a, ByteStr> { + #[inline] + fn from(s: &'a ByteString) -> Self { + Cow::Borrowed(s.as_bytestr()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromIterator<char> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self { + ByteString(iter.into_iter().collect::<String>().into_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromIterator<u8> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = u8>>(iter: T) -> Self { + ByteString(iter.into_iter().collect()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> FromIterator<&'a str> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self { + ByteString(iter.into_iter().collect::<String>().into_bytes()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> FromIterator<&'a [u8]> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = &'a [u8]>>(iter: T) -> Self { + let mut buf = Vec::new(); + for b in iter { + buf.extend_from_slice(b); + } + ByteString(buf) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> FromIterator<&'a ByteStr> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = &'a ByteStr>>(iter: T) -> Self { + let mut buf = Vec::new(); + for b in iter { + buf.extend_from_slice(&b.0); + } + ByteString(buf) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl FromIterator<ByteString> for ByteString { + #[inline] + fn from_iter<T: IntoIterator<Item = ByteString>>(iter: T) -> Self { + let mut buf = Vec::new(); + for mut b in iter { + buf.append(&mut b.0); + } + ByteString(buf) + } +} + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +#[unstable(feature = "bstr", issue = "134915")] +impl FromStr for ByteString { + type Err = core::convert::Infallible; + + #[inline] + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(ByteString(s.as_bytes().to_vec())) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<usize> for ByteString { + type Output = u8; + + #[inline] + fn index(&self, idx: usize) -> &u8 { + &self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeFull> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, _: RangeFull) -> &ByteStr { + self.as_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<Range<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: Range<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeInclusive<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeInclusive<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeFrom<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeFrom<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeTo<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeTo<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeToInclusive<usize>> for ByteString { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<usize> for ByteString { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut u8 { + &mut self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeFull> for ByteString { + #[inline] + fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr { + self.as_mut_bytestr() + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<Range<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeInclusive<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeFrom<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeTo<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeToInclusive<usize>> for ByteString { + #[inline] + fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl hash::Hash for ByteString { + #[inline] + fn hash<H: hash::Hasher>(&self, state: &mut H) { + self.0.hash(state); + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Eq for ByteString {} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialEq for ByteString { + #[inline] + fn eq(&self, other: &ByteString) -> bool { + self.0 == other.0 + } +} + +macro_rules! impl_partial_eq_ord_cow { + ($lhs:ty, $rhs:ty) => { + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = (&**other).as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = (&**self).as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> { + let other: &[u8] = (&**other).as_ref(); + PartialOrd::partial_cmp(self.as_bytes(), other) + } + } + + #[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> { + let this: &[u8] = (&**self).as_ref(); + PartialOrd::partial_cmp(this, other.as_bytes()) + } + } + }; +} + +// PartialOrd with `Vec<u8>` omitted to avoid inference failures +impl_partial_eq!(ByteString, Vec<u8>); +// PartialOrd with `[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteString, [u8]); +// PartialOrd with `&[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteString, &[u8]); +// PartialOrd with `String` omitted to avoid inference failures +impl_partial_eq!(ByteString, String); +// PartialOrd with `str` omitted to avoid inference failures +impl_partial_eq!(ByteString, str); +// PartialOrd with `&str` omitted to avoid inference failures +impl_partial_eq!(ByteString, &str); +impl_partial_eq_ord!(ByteString, ByteStr); +impl_partial_eq_ord!(ByteString, &ByteStr); +// PartialOrd with `[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteString, [u8; N]); +// PartialOrd with `&[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteString, &[u8; N]); +impl_partial_eq_ord_cow!(ByteString, Cow<'_, ByteStr>); +impl_partial_eq_ord_cow!(ByteString, Cow<'_, str>); +impl_partial_eq_ord_cow!(ByteString, Cow<'_, [u8]>); + +#[unstable(feature = "bstr", issue = "134915")] +impl Ord for ByteString { + #[inline] + fn cmp(&self, other: &ByteString) -> Ordering { + Ord::cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialOrd for ByteString { + #[inline] + fn partial_cmp(&self, other: &ByteString) -> Option<Ordering> { + PartialOrd::partial_cmp(&self.0, &other.0) + } +} + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +#[unstable(feature = "bstr", issue = "134915")] +impl ToOwned for ByteStr { + type Owned = ByteString; + + #[inline] + fn to_owned(&self) -> ByteString { + ByteString(self.0.to_vec()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl TryFrom<ByteString> for String { + type Error = crate::string::FromUtf8Error; + + #[inline] + fn try_from(s: ByteString) -> Result<Self, Self::Error> { + String::from_utf8(s.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a ByteString> for &'a str { + type Error = crate::str::Utf8Error; + + #[inline] + fn try_from(s: &'a ByteString) -> Result<Self, Self::Error> { + crate::str::from_utf8(s.0.as_slice()) + } +} + +// Additional impls for `ByteStr` that require types from `alloc`: + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +#[unstable(feature = "bstr", issue = "134915")] +impl Clone for Box<ByteStr> { + #[inline] + fn clone(&self) -> Self { + Self::from(Box::<[u8]>::from(&self.0)) + } +} + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> From<&'a ByteStr> for Cow<'a, ByteStr> { + #[inline] + fn from(s: &'a ByteStr) -> Self { + Cow::Borrowed(s) + } +} + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +#[unstable(feature = "bstr", issue = "134915")] +impl From<Box<[u8]>> for Box<ByteStr> { + #[inline] + fn from(s: Box<[u8]>) -> Box<ByteStr> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Box::from_raw(Box::into_raw(s) as _) } + } +} + +#[cfg(not(test))] // https://github.com/rust-lang/rust/issues/135100 +#[unstable(feature = "bstr", issue = "134915")] +impl From<Box<ByteStr>> for Box<[u8]> { + #[inline] + fn from(s: Box<ByteStr>) -> Box<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Box::from_raw(Box::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +#[cfg(not(no_rc))] +impl From<Rc<[u8]>> for Rc<ByteStr> { + #[inline] + fn from(s: Rc<[u8]>) -> Rc<ByteStr> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Rc::from_raw(Rc::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +#[cfg(not(no_rc))] +impl From<Rc<ByteStr>> for Rc<[u8]> { + #[inline] + fn from(s: Rc<ByteStr>) -> Rc<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Rc::from_raw(Rc::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] +impl From<Arc<[u8]>> for Arc<ByteStr> { + #[inline] + fn from(s: Arc<[u8]>) -> Arc<ByteStr> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Arc::from_raw(Arc::into_raw(s) as _) } + } +} + +#[unstable(feature = "bstr", issue = "134915")] +#[cfg(all(not(no_rc), not(no_sync), target_has_atomic = "ptr"))] +impl From<Arc<ByteStr>> for Arc<[u8]> { + #[inline] + fn from(s: Arc<ByteStr>) -> Arc<[u8]> { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`. + unsafe { Arc::from_raw(Arc::into_raw(s) as _) } + } +} + +// PartialOrd with `Vec<u8>` omitted to avoid inference failures +impl_partial_eq!(ByteStr, Vec<u8>); +// PartialOrd with `String` omitted to avoid inference failures +impl_partial_eq!(ByteStr, String); +impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, ByteStr>); +impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, str>); +impl_partial_eq_ord_cow!(&'a ByteStr, Cow<'a, [u8]>); + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a ByteStr> for String { + type Error = core::str::Utf8Error; + + #[inline] + fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> { + Ok(core::str::from_utf8(&s.0)?.into()) + } +} diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 9660023d694..041f80c1f2c 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1442,20 +1442,20 @@ impl<T, A: Allocator + Clone> BTreeSet<T, A> { /// /// let mut set = BTreeSet::from([1, 2, 3, 4]); /// - /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Included(&3)) }; + /// let mut cursor = set.upper_bound_mut(Bound::Included(&3)); /// assert_eq!(cursor.peek_prev(), Some(&3)); /// assert_eq!(cursor.peek_next(), Some(&4)); /// - /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Excluded(&3)) }; + /// let mut cursor = set.upper_bound_mut(Bound::Excluded(&3)); /// assert_eq!(cursor.peek_prev(), Some(&2)); /// assert_eq!(cursor.peek_next(), Some(&3)); /// - /// let mut cursor = unsafe { set.upper_bound_mut(Bound::Unbounded) }; + /// let mut cursor = set.upper_bound_mut(Bound::Unbounded); /// assert_eq!(cursor.peek_prev(), Some(&4)); /// assert_eq!(cursor.peek_next(), None); /// ``` #[unstable(feature = "btree_cursors", issue = "107540")] - pub unsafe fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> + pub fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, T, A> where T: Borrow<Q> + Ord, Q: Ord, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index b4f08debc93..28e4217e303 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -102,6 +102,8 @@ #![feature(async_fn_traits)] #![feature(async_iterator)] #![feature(box_uninit_write)] +#![feature(bstr)] +#![feature(bstr_internals)] #![feature(clone_to_uninit)] #![feature(coerce_unsized)] #![feature(const_eval_select)] @@ -228,6 +230,8 @@ mod boxed { pub use std::boxed::Box; } pub mod borrow; +#[unstable(feature = "bstr", issue = "134915")] +pub mod bstr; pub mod collections; #[cfg(all(not(no_rc), not(no_sync), not(no_global_oom_handling)))] pub mod ffi; diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs index cb130f60cec..81d828a971c 100644 --- a/library/core/src/arch.rs +++ b/library/core/src/arch.rs @@ -1,6 +1,14 @@ #![doc = include_str!("../../stdarch/crates/core_arch/src/core_arch_docs.md")] -#[allow(unused_imports)] +#[allow( + // some targets don't have anything to reexport, which + // makes the `pub use` unused and unreachable, allow + // both lints as to not have `#[cfg]`s + // + // cf. https://github.com/rust-lang/rust/pull/116033#issuecomment-1760085575 + unused_imports, + unreachable_pub +)] #[stable(feature = "simd_arch", since = "1.27.0")] pub use crate::core_arch::arch::*; diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 2ae5ded1fd5..28329bb0908 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -156,7 +156,6 @@ pub const fn from_mut<T>(s: &mut T) -> &mut [T; 1] { /// The error type returned when a conversion from a slice to an array fails. #[stable(feature = "try_from", since = "1.34.0")] -#[rustc_allowed_through_unstable_modules] #[derive(Debug, Copy, Clone)] pub struct TryFromSliceError(()); @@ -893,7 +892,7 @@ impl<T> Guard<'_, T> { /// /// No more than N elements must be initialized. #[inline] - pub unsafe fn push_unchecked(&mut self, item: T) { + pub(crate) unsafe fn push_unchecked(&mut self, item: T) { // SAFETY: If `initialized` was correct before and the caller does not // invoke this method more than N times then writes will be in-bounds // and slots will not be initialized more than once. diff --git a/library/core/src/bstr.rs b/library/core/src/bstr.rs new file mode 100644 index 00000000000..74e07f3d242 --- /dev/null +++ b/library/core/src/bstr.rs @@ -0,0 +1,581 @@ +//! The `ByteStr` type and trait implementations. + +use crate::borrow::{Borrow, BorrowMut}; +use crate::cmp::Ordering; +use crate::ops::{ + Deref, DerefMut, DerefPure, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, + RangeTo, RangeToInclusive, +}; +use crate::{fmt, hash}; + +/// A wrapper for `&[u8]` representing a human-readable string that's conventionally, but not +/// always, UTF-8. +/// +/// Unlike `&str`, this type permits non-UTF-8 contents, making it suitable for user input, +/// non-native filenames (as `Path` only supports native filenames), and other applications that +/// need to round-trip whatever data the user provides. +/// +/// For an owned, growable byte string buffer, use +/// [`ByteString`](../../std/bstr/struct.ByteString.html). +/// +/// `ByteStr` implements `Deref` to `[u8]`, so all methods available on `[u8]` are available on +/// `ByteStr`. +/// +/// # Representation +/// +/// A `&ByteStr` has the same representation as a `&str`. That is, a `&ByteStr` is a wide pointer +/// which includes a pointer to some bytes and a length. +/// +/// # Trait implementations +/// +/// The `ByteStr` type has a number of trait implementations, and in particular, defines equality +/// and comparisons between `&ByteStr`, `&str`, and `&[u8]`, for convenience. +/// +/// The `Debug` implementation for `ByteStr` shows its bytes as a normal string, with invalid UTF-8 +/// presented as hex escape sequences. +/// +/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a +/// `str`, with invalid UTF-8 presented as the Unicode replacement character: � +/// +#[unstable(feature = "bstr", issue = "134915")] +#[repr(transparent)] +#[doc(alias = "BStr")] +pub struct ByteStr(pub [u8]); + +impl ByteStr { + /// Creates a `ByteStr` slice from anything that can be converted to a byte slice. + /// + /// This is a zero-cost conversion. + /// + /// # Example + /// + /// You can create a `ByteStr` from a byte array, a byte slice or a string slice: + /// + /// ``` + /// # #![feature(bstr)] + /// # use std::bstr::ByteStr; + /// let a = ByteStr::new(b"abc"); + /// let b = ByteStr::new(&b"abc"[..]); + /// let c = ByteStr::new("abc"); + /// + /// assert_eq!(a, b); + /// assert_eq!(a, c); + /// ``` + #[inline] + #[unstable(feature = "bstr", issue = "134915")] + pub fn new<B: ?Sized + AsRef<[u8]>>(bytes: &B) -> &Self { + ByteStr::from_bytes(bytes.as_ref()) + } + + #[doc(hidden)] + #[unstable(feature = "bstr_internals", issue = "none")] + #[inline] + pub fn from_bytes(slice: &[u8]) -> &Self { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to + // the wrapped type into a reference to the wrapper type. + unsafe { &*(slice as *const [u8] as *const Self) } + } + + #[doc(hidden)] + #[unstable(feature = "bstr_internals", issue = "none")] + #[inline] + pub fn from_bytes_mut(slice: &mut [u8]) -> &mut Self { + // SAFETY: `ByteStr` is a transparent wrapper around `[u8]`, so we can turn a reference to + // the wrapped type into a reference to the wrapper type. + unsafe { &mut *(slice as *mut [u8] as *mut Self) } + } + + #[doc(hidden)] + #[unstable(feature = "bstr_internals", issue = "none")] + #[inline] + pub fn as_bytes(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Deref for ByteStr { + type Target = [u8]; + + #[inline] + fn deref(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl DerefMut for ByteStr { + #[inline] + fn deref_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "deref_pure_trait", issue = "87121")] +unsafe impl DerefPure for ByteStr {} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Debug for ByteStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "\"")?; + for chunk in self.utf8_chunks() { + for c in chunk.valid().chars() { + match c { + '\0' => write!(f, "\\0")?, + '\x01'..='\x7f' => write!(f, "{}", (c as u8).escape_ascii())?, + _ => write!(f, "{}", c.escape_debug())?, + } + } + write!(f, "{}", chunk.invalid().escape_ascii())?; + } + write!(f, "\"")?; + Ok(()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl fmt::Display for ByteStr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt_nopad(this: &ByteStr, f: &mut fmt::Formatter<'_>) -> fmt::Result { + for chunk in this.utf8_chunks() { + f.write_str(chunk.valid())?; + if !chunk.invalid().is_empty() { + f.write_str("\u{FFFD}")?; + } + } + Ok(()) + } + + let Some(align) = f.align() else { + return fmt_nopad(self, f); + }; + let nchars: usize = self + .utf8_chunks() + .map(|chunk| chunk.valid().len() + if chunk.invalid().is_empty() { 0 } else { 1 }) + .sum(); + let padding = f.width().unwrap_or(0).saturating_sub(nchars); + let fill = f.fill(); + let (lpad, rpad) = match align { + fmt::Alignment::Left => (0, padding), + fmt::Alignment::Right => (padding, 0), + fmt::Alignment::Center => { + let half = padding / 2; + (half, half + padding % 2) + } + }; + for _ in 0..lpad { + write!(f, "{fill}")?; + } + fmt_nopad(self, f)?; + for _ in 0..rpad { + write!(f, "{fill}")?; + } + + Ok(()) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<[u8]> for ByteStr { + #[inline] + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<ByteStr> for ByteStr { + #[inline] + fn as_ref(&self) -> &ByteStr { + self + } +} + +// `impl AsRef<ByteStr> for [u8]` omitted to avoid widespread inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl AsRef<ByteStr> for str { + #[inline] + fn as_ref(&self) -> &ByteStr { + ByteStr::new(self) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl AsMut<[u8]> for ByteStr { + #[inline] + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +// `impl AsMut<ByteStr> for [u8]` omitted to avoid widespread inference failures + +// `impl Borrow<ByteStr> for [u8]` omitted to avoid widespread inference failures + +// `impl Borrow<ByteStr> for str` omitted to avoid widespread inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl Borrow<[u8]> for ByteStr { + #[inline] + fn borrow(&self) -> &[u8] { + &self.0 + } +} + +// `impl BorrowMut<ByteStr> for [u8]` omitted to avoid widespread inference failures + +#[unstable(feature = "bstr", issue = "134915")] +impl BorrowMut<[u8]> for ByteStr { + #[inline] + fn borrow_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> Default for &'a ByteStr { + fn default() -> Self { + ByteStr::from_bytes(b"") + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> Default for &'a mut ByteStr { + fn default() -> Self { + ByteStr::from_bytes_mut(&mut []) + } +} + +// Omitted due to inference failures +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a, const N: usize> From<&'a [u8; N]> for &'a ByteStr { +// #[inline] +// fn from(s: &'a [u8; N]) -> Self { +// ByteStr::from_bytes(s) +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a [u8]> for &'a ByteStr { +// #[inline] +// fn from(s: &'a [u8]) -> Self { +// ByteStr::from_bytes(s) +// } +// } + +// Omitted due to slice-from-array-issue-113238: +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a ByteStr> for &'a [u8] { +// #[inline] +// fn from(s: &'a ByteStr) -> Self { +// &s.0 +// } +// } +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a mut ByteStr> for &'a mut [u8] { +// #[inline] +// fn from(s: &'a mut ByteStr) -> Self { +// &mut s.0 +// } +// } + +// Omitted due to inference failures +// +// #[unstable(feature = "bstr", issue = "134915")] +// impl<'a> From<&'a str> for &'a ByteStr { +// #[inline] +// fn from(s: &'a str) -> Self { +// ByteStr::from_bytes(s.as_bytes()) +// } +// } + +#[unstable(feature = "bstr", issue = "134915")] +impl hash::Hash for ByteStr { + #[inline] + fn hash<H: hash::Hasher>(&self, state: &mut H) { + self.0.hash(state); + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<usize> for ByteStr { + type Output = u8; + + #[inline] + fn index(&self, idx: usize) -> &u8 { + &self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeFull> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, _: RangeFull) -> &ByteStr { + self + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<Range<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: Range<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeInclusive<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeInclusive<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeFrom<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeFrom<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeTo<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeTo<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Index<RangeToInclusive<usize>> for ByteStr { + type Output = ByteStr; + + #[inline] + fn index(&self, r: RangeToInclusive<usize>) -> &ByteStr { + ByteStr::from_bytes(&self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<usize> for ByteStr { + #[inline] + fn index_mut(&mut self, idx: usize) -> &mut u8 { + &mut self.0[idx] + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeFull> for ByteStr { + #[inline] + fn index_mut(&mut self, _: RangeFull) -> &mut ByteStr { + self + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<Range<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: Range<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeInclusive<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeInclusive<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeFrom<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeFrom<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeTo<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeTo<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl IndexMut<RangeToInclusive<usize>> for ByteStr { + #[inline] + fn index_mut(&mut self, r: RangeToInclusive<usize>) -> &mut ByteStr { + ByteStr::from_bytes_mut(&mut self.0[r]) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl Eq for ByteStr {} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialEq<ByteStr> for ByteStr { + #[inline] + fn eq(&self, other: &ByteStr) -> bool { + &self.0 == &other.0 + } +} + +#[doc(hidden)] +#[macro_export] +#[unstable(feature = "bstr_internals", issue = "none")] +macro_rules! impl_partial_eq { + ($lhs:ty, $rhs:ty) => { + #[allow(unused_lifetimes)] + impl<'a> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = other.as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + impl<'a> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = self.as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + }; +} + +#[doc(hidden)] +#[unstable(feature = "bstr_internals", issue = "none")] +pub use impl_partial_eq; + +#[doc(hidden)] +#[macro_export] +#[unstable(feature = "bstr_internals", issue = "none")] +macro_rules! impl_partial_eq_ord { + ($lhs:ty, $rhs:ty) => { + $crate::bstr::impl_partial_eq!($lhs, $rhs); + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option<Ordering> { + let other: &[u8] = other.as_ref(); + PartialOrd::partial_cmp(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<'a> PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option<Ordering> { + let this: &[u8] = self.as_ref(); + PartialOrd::partial_cmp(this, other.as_bytes()) + } + } + }; +} + +#[doc(hidden)] +#[unstable(feature = "bstr_internals", issue = "none")] +pub use impl_partial_eq_ord; + +#[doc(hidden)] +#[macro_export] +#[unstable(feature = "bstr_internals", issue = "none")] +macro_rules! impl_partial_eq_n { + ($lhs:ty, $rhs:ty) => { + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<const N: usize> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + let other: &[u8] = other.as_ref(); + PartialEq::eq(self.as_bytes(), other) + } + } + + #[allow(unused_lifetimes)] + #[unstable(feature = "bstr", issue = "134915")] + impl<const N: usize> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + let this: &[u8] = self.as_ref(); + PartialEq::eq(this, other.as_bytes()) + } + } + }; +} + +#[doc(hidden)] +#[unstable(feature = "bstr_internals", issue = "none")] +pub use impl_partial_eq_n; + +// PartialOrd with `[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteStr, [u8]); +// PartialOrd with `&[u8]` omitted to avoid inference failures +impl_partial_eq!(ByteStr, &[u8]); +// PartialOrd with `str` omitted to avoid inference failures +impl_partial_eq!(ByteStr, str); +// PartialOrd with `&str` omitted to avoid inference failures +impl_partial_eq!(ByteStr, &str); +// PartialOrd with `[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteStr, [u8; N]); +// PartialOrd with `[u8; N]` omitted to avoid inference failures +impl_partial_eq_n!(ByteStr, &[u8; N]); + +#[unstable(feature = "bstr", issue = "134915")] +impl Ord for ByteStr { + #[inline] + fn cmp(&self, other: &ByteStr) -> Ordering { + Ord::cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl PartialOrd for ByteStr { + #[inline] + fn partial_cmp(&self, other: &ByteStr) -> Option<Ordering> { + PartialOrd::partial_cmp(&self.0, &other.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a ByteStr> for &'a str { + type Error = crate::str::Utf8Error; + + #[inline] + fn try_from(s: &'a ByteStr) -> Result<Self, Self::Error> { + crate::str::from_utf8(&s.0) + } +} + +#[unstable(feature = "bstr", issue = "134915")] +impl<'a> TryFrom<&'a mut ByteStr> for &'a mut str { + type Error = crate::str::Utf8Error; + + #[inline] + fn try_from(s: &'a mut ByteStr) -> Result<Self, Self::Error> { + crate::str::from_utf8_mut(&mut s.0) + } +} diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 306d565a77e..20187e478aa 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -22,8 +22,8 @@ //! (mutable via `&T`), in contrast with typical Rust types that exhibit 'inherited mutability' //! (mutable only via `&mut T`). //! -//! Cell types come in three flavors: `Cell<T>`, `RefCell<T>`, and `OnceCell<T>`. Each provides -//! a different way of providing safe interior mutability. +//! Cell types come in four flavors: `Cell<T>`, `RefCell<T>`, `OnceCell<T>`, and `LazyCell<T>`. +//! Each provides a different way of providing safe interior mutability. //! //! ## `Cell<T>` //! diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index ec1aed53eaf..00300328b64 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -311,6 +311,16 @@ unsafe impl CloneToUninit for crate::ffi::CStr { } } +#[unstable(feature = "bstr", issue = "134915")] +unsafe impl CloneToUninit for crate::bstr::ByteStr { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: ByteStr is a `#[repr(transparent)]` wrapper around `[u8]` + unsafe { self.as_bytes().clone_to_uninit(dst) } + } +} + /// Implementations of `Clone` for primitive types. /// /// Implementations that cannot be described in Rust diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs index 0685f525dca..0c3329f676e 100644 --- a/library/core/src/escape.rs +++ b/library/core/src/escape.rs @@ -163,28 +163,28 @@ pub(crate) struct EscapeIterInner<const N: usize> { } impl<const N: usize> EscapeIterInner<N> { - pub const fn backslash(c: ascii::Char) -> Self { + pub(crate) const fn backslash(c: ascii::Char) -> Self { let (data, range) = backslash(c); Self { data, alive: range } } - pub const fn ascii(c: u8) -> Self { + pub(crate) const fn ascii(c: u8) -> Self { let (data, range) = escape_ascii(c); Self { data, alive: range } } - pub const fn unicode(c: char) -> Self { + pub(crate) const fn unicode(c: char) -> Self { let (data, range) = escape_unicode(c); Self { data, alive: range } } #[inline] - pub const fn empty() -> Self { + pub(crate) const fn empty() -> Self { Self { data: [ascii::Char::Null; N], alive: 0..0 } } #[inline] - pub fn as_ascii(&self) -> &[ascii::Char] { + pub(crate) fn as_ascii(&self) -> &[ascii::Char] { // SAFETY: `self.alive` is guaranteed to be a valid range for indexing `self.data`. unsafe { self.data.get_unchecked(usize::from(self.alive.start)..usize::from(self.alive.end)) @@ -192,34 +192,34 @@ impl<const N: usize> EscapeIterInner<N> { } #[inline] - pub fn as_str(&self) -> &str { + pub(crate) fn as_str(&self) -> &str { self.as_ascii().as_str() } #[inline] - pub fn len(&self) -> usize { + pub(crate) fn len(&self) -> usize { usize::from(self.alive.end - self.alive.start) } - pub fn next(&mut self) -> Option<u8> { + pub(crate) fn next(&mut self) -> Option<u8> { let i = self.alive.next()?; // SAFETY: `i` is guaranteed to be a valid index for `self.data`. unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) } } - pub fn next_back(&mut self) -> Option<u8> { + pub(crate) fn next_back(&mut self) -> Option<u8> { let i = self.alive.next_back()?; // SAFETY: `i` is guaranteed to be a valid index for `self.data`. unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) } } - pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { + pub(crate) fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { self.alive.advance_by(n) } - pub fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { + pub(crate) fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> { self.alive.advance_back_by(n) } } diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index 5f32775822b..79d094556c4 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -172,10 +172,10 @@ mod c_char_definition { target_arch = "xtensa", ) ))] { - pub type c_char = u8; + pub(super) type c_char = u8; } else { // On every other target, c_char is signed. - pub type c_char = i8; + pub(super) type c_char = i8; } } } @@ -183,11 +183,11 @@ mod c_char_definition { mod c_int_definition { cfg_if! { if #[cfg(any(target_arch = "avr", target_arch = "msp430"))] { - pub type c_int = i16; - pub type c_uint = u16; + pub(super) type c_int = i16; + pub(super) type c_uint = u16; } else { - pub type c_int = i32; - pub type c_uint = u32; + pub(super) type c_int = i32; + pub(super) type c_uint = u32; } } } @@ -195,12 +195,12 @@ mod c_int_definition { mod c_long_definition { cfg_if! { if #[cfg(all(target_pointer_width = "64", not(windows)))] { - pub type c_long = i64; - pub type c_ulong = u64; + pub(super) type c_long = i64; + pub(super) type c_ulong = u64; } else { // The minimal size of `long` in the C standard is 32 bits - pub type c_long = i32; - pub type c_ulong = u32; + pub(super) type c_long = i32; + pub(super) type c_ulong = u32; } } } diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 9c054b99a27..80f6e32b6b2 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -597,3 +597,138 @@ pub const fn black_box<T>(dummy: T) -> T { pub const fn must_use<T>(value: T) -> T { value } + +/// Hints to the compiler that a branch condition is likely to be true. +/// Returns the value passed to it. +/// +/// It can be used with `if` or boolean `match` expressions. +/// +/// When used outside of a branch condition, it may still influence a nearby branch, but +/// probably will not have any effect. +/// +/// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to +/// compound expressions, such as `likely(a && b)`. When applied to compound expressions, it has +/// the following effect: +/// ```text +/// likely(!a) => !unlikely(a) +/// likely(a && b) => likely(a) && likely(b) +/// likely(a || b) => a || likely(b) +/// ``` +/// +/// See also the function [`cold_path()`] which may be more appropriate for idiomatic Rust code. +/// +/// # Examples +/// +/// ``` +/// #![feature(likely_unlikely)] +/// use core::hint::likely; +/// +/// fn foo(x: i32) { +/// if likely(x > 0) { +/// println!("this branch is likely to be taken"); +/// } else { +/// println!("this branch is unlikely to be taken"); +/// } +/// +/// match likely(x > 0) { +/// true => println!("this branch is likely to be taken"), +/// false => println!("this branch is unlikely to be taken"), +/// } +/// +/// // Use outside of a branch condition may still influence a nearby branch +/// let cond = likely(x != 0); +/// if cond { +/// println!("this branch is likely to be taken"); +/// } +/// } +/// ``` +/// +/// +#[unstable(feature = "likely_unlikely", issue = "26179")] +#[inline(always)] +pub const fn likely(b: bool) -> bool { + crate::intrinsics::likely(b) +} + +/// Hints to the compiler that a branch condition is unlikely to be true. +/// Returns the value passed to it. +/// +/// It can be used with `if` or boolean `match` expressions. +/// +/// When used outside of a branch condition, it may still influence a nearby branch, but +/// probably will not have any effect. +/// +/// It can also be applied to parts of expressions, such as `likely(a) && unlikely(b)`, or to +/// compound expressions, such as `unlikely(a && b)`. When applied to compound expressions, it has +/// the following effect: +/// ```text +/// unlikely(!a) => !likely(a) +/// unlikely(a && b) => a && unlikely(b) +/// unlikely(a || b) => unlikely(a) || unlikely(b) +/// ``` +/// +/// See also the function [`cold_path()`] which may be more appropriate for idiomatic Rust code. +/// +/// # Examples +/// +/// ``` +/// #![feature(likely_unlikely)] +/// use core::hint::unlikely; +/// +/// fn foo(x: i32) { +/// if unlikely(x > 0) { +/// println!("this branch is unlikely to be taken"); +/// } else { +/// println!("this branch is likely to be taken"); +/// } +/// +/// match unlikely(x > 0) { +/// true => println!("this branch is unlikely to be taken"), +/// false => println!("this branch is likely to be taken"), +/// } +/// +/// // Use outside of a branch condition may still influence a nearby branch +/// let cond = unlikely(x != 0); +/// if cond { +/// println!("this branch is likely to be taken"); +/// } +/// } +/// ``` +#[unstable(feature = "likely_unlikely", issue = "26179")] +#[inline(always)] +pub const fn unlikely(b: bool) -> bool { + crate::intrinsics::unlikely(b) +} + +/// Hints to the compiler that given path is cold, i.e., unlikely to be taken. The compiler may +/// choose to optimize paths that are not cold at the expense of paths that are cold. +/// +/// # Examples +/// +/// ``` +/// #![feature(cold_path)] +/// use core::hint::cold_path; +/// +/// fn foo(x: &[i32]) { +/// if let Some(first) = x.get(0) { +/// // this is the fast path +/// } else { +/// // this path is unlikely +/// cold_path(); +/// } +/// } +/// +/// fn bar(x: i32) -> i32 { +/// match x { +/// 1 => 10, +/// 2 => 100, +/// 3 => { cold_path(); 1000 }, // this branch is unlikely +/// _ => { cold_path(); 10000 }, // this is also unlikely +/// } +/// } +/// ``` +#[unstable(feature = "cold_path", issue = "26179")] +#[inline(always)] +pub const fn cold_path() { + crate::intrinsics::cold_path() +} diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 834f44c7790..55dcf7cd47e 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -233,7 +233,7 @@ //! //! - Operands implicitly convert to `Use` rvalues. //! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue. -//! - [`Discriminant`] and [`CopyForDeref`] have associated functions. +//! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions. //! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc. //! - The binary operation `Offset` can be created via [`Offset`]. //! - Checked binary operations are represented by wrapping the associated binop in [`Checked`]. @@ -401,6 +401,7 @@ define!("mir_storage_dead", fn StorageDead<T>(local: T)); define!("mir_assume", fn Assume(operand: bool)); define!("mir_deinit", fn Deinit<T>(place: T)); define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool)); +define!("mir_len", fn Len<T>(place: T) -> usize); define!( "mir_ptr_metadata", fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index e845bb34426..01ed3cc69a2 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -101,6 +101,7 @@ #![warn(multiple_supertrait_upcastable)] #![allow(internal_features)] #![deny(ffi_unwind_calls)] +#![warn(unreachable_pub)] // Do not check link redundancy on bootstraping phase #![allow(rustdoc::redundant_explicit_links)] #![warn(rustdoc::unescaped_backticks)] @@ -110,6 +111,8 @@ #![feature(array_ptr_get)] #![feature(asm_experimental_arch)] #![feature(bigint_helper_methods)] +#![feature(bstr)] +#![feature(bstr_internals)] #![feature(const_carrying_mul_add)] #![feature(const_eval_select)] #![feature(core_intrinsics)] @@ -335,6 +338,8 @@ pub mod ascii; pub mod asserting; #[unstable(feature = "async_iterator", issue = "79024")] pub mod async_iter; +#[unstable(feature = "bstr", issue = "134915")] +pub mod bstr; pub mod cell; pub mod char; pub mod ffi; @@ -396,7 +401,8 @@ pub mod primitive; unused_imports, unsafe_op_in_unsafe_fn, ambiguous_glob_reexports, - deprecated_in_future + deprecated_in_future, + unreachable_pub )] #[allow(rustdoc::bare_urls)] mod core_arch; diff --git a/library/core/src/net/display_buffer.rs b/library/core/src/net/display_buffer.rs index a7d12217081..625ad5401f5 100644 --- a/library/core/src/net/display_buffer.rs +++ b/library/core/src/net/display_buffer.rs @@ -2,19 +2,19 @@ use crate::mem::MaybeUninit; use crate::{fmt, str}; /// Used for slow path in `Display` implementations when alignment is required. -pub struct DisplayBuffer<const SIZE: usize> { +pub(super) struct DisplayBuffer<const SIZE: usize> { buf: [MaybeUninit<u8>; SIZE], len: usize, } impl<const SIZE: usize> DisplayBuffer<SIZE> { #[inline] - pub const fn new() -> Self { + pub(super) const fn new() -> Self { Self { buf: [MaybeUninit::uninit(); SIZE], len: 0 } } #[inline] - pub fn as_str(&self) -> &str { + pub(super) fn as_str(&self) -> &str { // SAFETY: `buf` is only written to by the `fmt::Write::write_str` implementation // which writes a valid UTF-8 string to `buf` and correctly sets `len`. unsafe { diff --git a/library/core/src/net/ip_addr.rs b/library/core/src/net/ip_addr.rs index 7dd5c214012..b11ba056853 100644 --- a/library/core/src/net/ip_addr.rs +++ b/library/core/src/net/ip_addr.rs @@ -1539,8 +1539,9 @@ impl Ipv6Addr { /// // Addresses reserved for benchmarking (`2001:2::/48`) /// assert_eq!(Ipv6Addr::new(0x2001, 2, 0, 0, 0, 0, 0, 1,).is_global(), false); /// - /// // Addresses reserved for documentation (`2001:db8::/32`) + /// // Addresses reserved for documentation (`2001:db8::/32` and `3fff::/20`) /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 1).is_global(), false); + /// assert_eq!(Ipv6Addr::new(0x3fff, 0, 0, 0, 0, 0, 0, 0).is_global(), false); /// /// // Unique local addresses (`fc00::/7`) /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 1).is_global(), false); @@ -1686,11 +1687,12 @@ impl Ipv6Addr { } /// Returns [`true`] if this is an address reserved for documentation - /// (`2001:db8::/32`). + /// (`2001:db8::/32` and `3fff::/20`). /// - /// This property is defined in [IETF RFC 3849]. + /// This property is defined by [IETF RFC 3849] and [IETF RFC 9637]. /// /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 + /// [IETF RFC 9637]: https://tools.ietf.org/html/rfc9637 /// /// # Examples /// @@ -1701,12 +1703,13 @@ impl Ipv6Addr { /// /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); + /// assert_eq!(Ipv6Addr::new(0x3fff, 0, 0, 0, 0, 0, 0, 0).is_documentation(), true); /// ``` #[unstable(feature = "ip", issue = "27709")] #[must_use] #[inline] pub const fn is_documentation(&self) -> bool { - (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) + matches!(self.segments(), [0x2001, 0xdb8, ..] | [0x3fff, 0..=0x0fff, ..]) } /// Returns [`true`] if this is an address reserved for benchmarking (`2001:2::/48`). diff --git a/library/core/src/num/dec2flt/decimal.rs b/library/core/src/num/dec2flt/decimal.rs index be9c0eccd5e..b37724ba62d 100644 --- a/library/core/src/num/dec2flt/decimal.rs +++ b/library/core/src/num/dec2flt/decimal.rs @@ -12,7 +12,7 @@ use crate::num::dec2flt::common::{ByteSlice, is_8digits}; #[derive(Clone)] -pub struct Decimal { +pub(super) struct Decimal { /// The number of significant digits in the decimal. pub num_digits: usize, /// The offset of the decimal point in the significant digits. @@ -55,13 +55,13 @@ impl Decimal { /// /// In Python: /// `-emin + p2 + math.floor((emin+ 1)*math.log(2, b)-math.log(1-2**(-p2), b))` - pub const MAX_DIGITS: usize = 768; + pub(super) const MAX_DIGITS: usize = 768; /// The max digits that can be exactly represented in a 64-bit integer. - pub const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19; - pub const DECIMAL_POINT_RANGE: i32 = 2047; + pub(super) const MAX_DIGITS_WITHOUT_OVERFLOW: usize = 19; + pub(super) const DECIMAL_POINT_RANGE: i32 = 2047; /// Append a digit to the buffer. - pub fn try_add_digit(&mut self, digit: u8) { + pub(super) fn try_add_digit(&mut self, digit: u8) { if self.num_digits < Self::MAX_DIGITS { self.digits[self.num_digits] = digit; } @@ -69,7 +69,7 @@ impl Decimal { } /// Trim trailing zeros from the buffer. - pub fn trim(&mut self) { + pub(super) fn trim(&mut self) { // All of the following calls to `Decimal::trim` can't panic because: // // 1. `parse_decimal` sets `num_digits` to a max of `Decimal::MAX_DIGITS`. @@ -83,7 +83,7 @@ impl Decimal { } } - pub fn round(&self) -> u64 { + pub(super) fn round(&self) -> u64 { if self.num_digits == 0 || self.decimal_point < 0 { return 0; } else if self.decimal_point > 18 { @@ -111,7 +111,7 @@ impl Decimal { } /// Computes decimal * 2^shift. - pub fn left_shift(&mut self, shift: usize) { + pub(super) fn left_shift(&mut self, shift: usize) { if self.num_digits == 0 { return; } @@ -152,7 +152,7 @@ impl Decimal { } /// Computes decimal * 2^-shift. - pub fn right_shift(&mut self, shift: usize) { + pub(super) fn right_shift(&mut self, shift: usize) { let mut read_index = 0; let mut write_index = 0; let mut n = 0_u64; @@ -202,7 +202,7 @@ impl Decimal { } /// Parse a big integer representation of the float as a decimal. -pub fn parse_decimal(mut s: &[u8]) -> Decimal { +pub(super) fn parse_decimal(mut s: &[u8]) -> Decimal { let mut d = Decimal::default(); let start = s; diff --git a/library/core/src/num/dec2flt/fpu.rs b/library/core/src/num/dec2flt/fpu.rs index 8d62684f8d3..daeee1755b0 100644 --- a/library/core/src/num/dec2flt/fpu.rs +++ b/library/core/src/num/dec2flt/fpu.rs @@ -1,7 +1,7 @@ //! Platform-specific, assembly instructions to avoid //! intermediate rounding on architectures with FPUs. -pub use fpu_precision::set_precision; +pub(super) use fpu_precision::set_precision; // On x86, the x87 FPU is used for float operations if the SSE/SSE2 extensions are not available. // The x87 FPU operates with 80 bits of precision by default, which means that operations will @@ -42,7 +42,7 @@ mod fpu_precision { /// - 0b10, double precision i.e., 64-bits /// - 0b11, double extended precision i.e., 80-bits (default state) /// The 0b01 value is reserved and should not be used. - pub struct FPUControlWord(u16); + pub(crate) struct FPUControlWord(u16); fn set_cw(cw: u16) { // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with @@ -57,7 +57,7 @@ mod fpu_precision { } /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`. - pub fn set_precision<T>() -> FPUControlWord { + pub(crate) fn set_precision<T>() -> FPUControlWord { let mut cw = 0_u16; // Compute the value for the Precision Control field that is appropriate for `T`. @@ -97,5 +97,5 @@ mod fpu_precision { // precision of the computation is determined on a per-operation basis. #[cfg(any(not(target_arch = "x86"), target_feature = "sse2"))] mod fpu_precision { - pub fn set_precision<T>() {} + pub(crate) fn set_precision<T>() {} } diff --git a/library/core/src/num/dec2flt/table.rs b/library/core/src/num/dec2flt/table.rs index 4856074a62b..942c2eacfd2 100644 --- a/library/core/src/num/dec2flt/table.rs +++ b/library/core/src/num/dec2flt/table.rs @@ -6,16 +6,17 @@ //! //! DO NOT MODIFY: Generated by `src/etc/dec2flt_table.py` -pub const SMALLEST_POWER_OF_FIVE: i32 = -342; -pub const LARGEST_POWER_OF_FIVE: i32 = 308; -pub const N_POWERS_OF_FIVE: usize = (LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize; +pub(super) const SMALLEST_POWER_OF_FIVE: i32 = -342; +pub(super) const LARGEST_POWER_OF_FIVE: i32 = 308; +pub(super) const N_POWERS_OF_FIVE: usize = + (LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize; // Use static to avoid long compile times: Rust compiler errors // can have the entire table compiled multiple times, and then // emit code multiple times, even if it's stripped out in // the final binary. #[rustfmt::skip] -pub static POWER_OF_FIVE_128: [(u64, u64); N_POWERS_OF_FIVE] = [ +pub(super) static POWER_OF_FIVE_128: [(u64, u64); N_POWERS_OF_FIVE] = [ (0xeef453d6923bd65a, 0x113faa2906a13b3f), // 5^-342 (0x9558b4661b6565f8, 0x4ac7ca59a424c507), // 5^-341 (0xbaaee17fa23ebf76, 0x5d79bcf00d2df649), // 5^-340 diff --git a/library/core/src/num/int_log10.rs b/library/core/src/num/int_log10.rs index 0ce31b40a38..28a3f5d880a 100644 --- a/library/core/src/num/int_log10.rs +++ b/library/core/src/num/int_log10.rs @@ -3,7 +3,7 @@ // 0 < val <= u8::MAX #[inline] -pub const fn u8(val: u8) -> u32 { +pub(super) const fn u8(val: u8) -> u32 { let val = val as u32; // For better performance, avoid branches by assembling the solution @@ -45,13 +45,13 @@ const fn less_than_5(val: u32) -> u32 { // 0 < val <= u16::MAX #[inline] -pub const fn u16(val: u16) -> u32 { +pub(super) const fn u16(val: u16) -> u32 { less_than_5(val as u32) } // 0 < val <= u32::MAX #[inline] -pub const fn u32(mut val: u32) -> u32 { +pub(super) const fn u32(mut val: u32) -> u32 { let mut log = 0; if val >= 100_000 { val /= 100_000; @@ -62,7 +62,7 @@ pub const fn u32(mut val: u32) -> u32 { // 0 < val <= u64::MAX #[inline] -pub const fn u64(mut val: u64) -> u32 { +pub(super) const fn u64(mut val: u64) -> u32 { let mut log = 0; if val >= 10_000_000_000 { val /= 10_000_000_000; @@ -77,7 +77,7 @@ pub const fn u64(mut val: u64) -> u32 { // 0 < val <= u128::MAX #[inline] -pub const fn u128(mut val: u128) -> u32 { +pub(super) const fn u128(mut val: u128) -> u32 { let mut log = 0; if val >= 100_000_000_000_000_000_000_000_000_000_000 { val /= 100_000_000_000_000_000_000_000_000_000_000; @@ -93,49 +93,49 @@ pub const fn u128(mut val: u128) -> u32 { #[cfg(target_pointer_width = "16")] #[inline] -pub const fn usize(val: usize) -> u32 { +pub(super) const fn usize(val: usize) -> u32 { u16(val as _) } #[cfg(target_pointer_width = "32")] #[inline] -pub const fn usize(val: usize) -> u32 { +pub(super) const fn usize(val: usize) -> u32 { u32(val as _) } #[cfg(target_pointer_width = "64")] #[inline] -pub const fn usize(val: usize) -> u32 { +pub(super) const fn usize(val: usize) -> u32 { u64(val as _) } // 0 < val <= i8::MAX #[inline] -pub const fn i8(val: i8) -> u32 { +pub(super) const fn i8(val: i8) -> u32 { u8(val as u8) } // 0 < val <= i16::MAX #[inline] -pub const fn i16(val: i16) -> u32 { +pub(super) const fn i16(val: i16) -> u32 { u16(val as u16) } // 0 < val <= i32::MAX #[inline] -pub const fn i32(val: i32) -> u32 { +pub(super) const fn i32(val: i32) -> u32 { u32(val as u32) } // 0 < val <= i64::MAX #[inline] -pub const fn i64(val: i64) -> u32 { +pub(super) const fn i64(val: i64) -> u32 { u64(val as u64) } // 0 < val <= i128::MAX #[inline] -pub const fn i128(val: i128) -> u32 { +pub(super) const fn i128(val: i128) -> u32 { u128(val as u128) } @@ -143,6 +143,6 @@ pub const fn i128(val: i128) -> u32 { /// on every single primitive type. #[cold] #[track_caller] -pub const fn panic_for_nonpositive_argument() -> ! { +pub(super) const fn panic_for_nonpositive_argument() -> ! { panic!("argument of integer logarithm must be positive") } diff --git a/library/core/src/num/int_sqrt.rs b/library/core/src/num/int_sqrt.rs index 601e81f6993..c7a322c08c1 100644 --- a/library/core/src/num/int_sqrt.rs +++ b/library/core/src/num/int_sqrt.rs @@ -37,7 +37,7 @@ const U8_ISQRT_WITH_REMAINDER: [(u8, u8); 256] = { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] -pub const fn u8(n: u8) -> u8 { +pub(super) const fn u8(n: u8) -> u8 { U8_ISQRT_WITH_REMAINDER[n as usize].0 } @@ -58,7 +58,7 @@ macro_rules! signed_fn { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const unsafe fn $SignedT(n: $SignedT) -> $SignedT { + pub(super) const unsafe fn $SignedT(n: $SignedT) -> $SignedT { debug_assert!(n >= 0, "Negative input inside `isqrt`."); $UnsignedT(n as $UnsignedT) as $SignedT } @@ -83,7 +83,7 @@ macro_rules! unsigned_fn { #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn $UnsignedT(mut n: $UnsignedT) -> $UnsignedT { + pub(super) const fn $UnsignedT(mut n: $UnsignedT) -> $UnsignedT { if n <= <$HalfBitsT>::MAX as $UnsignedT { $HalfBitsT(n as $HalfBitsT) as $UnsignedT } else { @@ -311,6 +311,6 @@ unsigned_fn!(u128, u64, u128_stages); /// on every single primitive type. #[cold] #[track_caller] -pub const fn panic_for_negative_argument() -> ! { +pub(super) const fn panic_for_negative_argument() -> ! { panic!("argument of integer square root cannot be negative") } diff --git a/library/core/src/num/overflow_panic.rs b/library/core/src/num/overflow_panic.rs index 203037ffb43..e30573dd3f3 100644 --- a/library/core/src/num/overflow_panic.rs +++ b/library/core/src/num/overflow_panic.rs @@ -4,48 +4,48 @@ #[cold] #[track_caller] -pub const fn add() -> ! { +pub(super) const fn add() -> ! { panic!("attempt to add with overflow") } #[cold] #[track_caller] -pub const fn sub() -> ! { +pub(super) const fn sub() -> ! { panic!("attempt to subtract with overflow") } #[cold] #[track_caller] -pub const fn mul() -> ! { +pub(super) const fn mul() -> ! { panic!("attempt to multiply with overflow") } #[cold] #[track_caller] -pub const fn div() -> ! { +pub(super) const fn div() -> ! { panic!("attempt to divide with overflow") } #[cold] #[track_caller] -pub const fn rem() -> ! { +pub(super) const fn rem() -> ! { panic!("attempt to calculate the remainder with overflow") } #[cold] #[track_caller] -pub const fn neg() -> ! { +pub(super) const fn neg() -> ! { panic!("attempt to negate with overflow") } #[cold] #[track_caller] -pub const fn shr() -> ! { +pub(super) const fn shr() -> ! { panic!("attempt to shift right with overflow") } #[cold] #[track_caller] -pub const fn shl() -> ! { +pub(super) const fn shl() -> ! { panic!("attempt to shift left with overflow") } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 404e4bcffd3..c8433b3bb16 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2663,8 +2663,8 @@ macro_rules! uint_impl { /// /// Basic usage: /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. + /// Please note that this example is shared between integer types, + /// which explains why `u32` is used here. /// /// ``` /// #![feature(bigint_helper_methods)] @@ -2677,6 +2677,35 @@ macro_rules! uint_impl { "(", stringify!($SelfT), "::MAX, ", stringify!($SelfT), "::MAX));" )] /// ``` + /// + /// This is the core per-digit operation for "grade school" O(n²) multiplication. + /// + /// Please note that this example is shared between integer types, + /// using `u8` for simplicity of the demonstration. + /// + /// ``` + /// #![feature(bigint_helper_methods)] + /// + /// fn quadratic_mul<const N: usize>(a: [u8; N], b: [u8; N]) -> [u8; N] { + /// let mut out = [0; N]; + /// for j in 0..N { + /// let mut carry = 0; + /// for i in 0..(N - j) { + /// (out[j + i], carry) = u8::carrying_mul_add(a[i], b[j], out[j + i], carry); + /// } + /// } + /// out + /// } + /// + /// // -1 * -1 == 1 + /// assert_eq!(quadratic_mul([0xFF; 3], [0xFF; 3]), [1, 0, 0]); + /// + /// assert_eq!(u32::wrapping_mul(0x9e3779b9, 0x7f4a7c15), 0xCFFC982D); + /// assert_eq!( + /// quadratic_mul(u32::to_le_bytes(0x9e3779b9), u32::to_le_bytes(0x7f4a7c15)), + /// u32::to_le_bytes(0xCFFC982D) + /// ); + /// ``` #[unstable(feature = "bigint_helper_methods", issue = "85532")] #[rustc_const_unstable(feature = "bigint_helper_methods", issue = "85532")] #[must_use = "this returns the result of the operation, \ diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index 1156b389e28..55fa91d0b9f 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -1058,33 +1058,33 @@ mod shift_max { #[cfg(target_pointer_width = "16")] mod platform { - pub const usize: u32 = super::u16; - pub const isize: u32 = super::i16; + pub(crate) const usize: u32 = super::u16; + pub(crate) const isize: u32 = super::i16; } #[cfg(target_pointer_width = "32")] mod platform { - pub const usize: u32 = super::u32; - pub const isize: u32 = super::i32; + pub(crate) const usize: u32 = super::u32; + pub(crate) const isize: u32 = super::i32; } #[cfg(target_pointer_width = "64")] mod platform { - pub const usize: u32 = super::u64; - pub const isize: u32 = super::i64; + pub(crate) const usize: u32 = super::u64; + pub(crate) const isize: u32 = super::i64; } - pub const i8: u32 = (1 << 3) - 1; - pub const i16: u32 = (1 << 4) - 1; - pub const i32: u32 = (1 << 5) - 1; - pub const i64: u32 = (1 << 6) - 1; - pub const i128: u32 = (1 << 7) - 1; - pub use self::platform::isize; - - pub const u8: u32 = i8; - pub const u16: u32 = i16; - pub const u32: u32 = i32; - pub const u64: u32 = i64; - pub const u128: u32 = i128; - pub use self::platform::usize; + pub(super) const i8: u32 = (1 << 3) - 1; + pub(super) const i16: u32 = (1 << 4) - 1; + pub(super) const i32: u32 = (1 << 5) - 1; + pub(super) const i64: u32 = (1 << 6) - 1; + pub(super) const i128: u32 = (1 << 7) - 1; + pub(super) use self::platform::isize; + + pub(super) const u8: u32 = i8; + pub(super) const u16: u32 = i16; + pub(super) const u32: u32 = i32; + pub(super) const u64: u32 = i64; + pub(super) const u128: u32 = i128; + pub(super) use self::platform::usize; } diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs index dce3514a159..b82184b15b2 100644 --- a/library/core/src/ops/index_range.rs +++ b/library/core/src/ops/index_range.rs @@ -18,7 +18,7 @@ impl IndexRange { /// # Safety /// - `start <= end` #[inline] - pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self { + pub(crate) const unsafe fn new_unchecked(start: usize, end: usize) -> Self { ub_checks::assert_unsafe_precondition!( check_library_ub, "IndexRange::new_unchecked requires `start <= end`", @@ -28,22 +28,22 @@ impl IndexRange { } #[inline] - pub const fn zero_to(end: usize) -> Self { + pub(crate) const fn zero_to(end: usize) -> Self { IndexRange { start: 0, end } } #[inline] - pub const fn start(&self) -> usize { + pub(crate) const fn start(&self) -> usize { self.start } #[inline] - pub const fn end(&self) -> usize { + pub(crate) const fn end(&self) -> usize { self.end } #[inline] - pub const fn len(&self) -> usize { + pub(crate) const fn len(&self) -> usize { // SAFETY: By invariant, this cannot wrap // Using the intrinsic because a UB check here impedes LLVM optimization. (#131563) unsafe { crate::intrinsics::unchecked_sub(self.end, self.start) } @@ -79,7 +79,7 @@ impl IndexRange { /// /// This is designed to help implement `Iterator::advance_by`. #[inline] - pub fn take_prefix(&mut self, n: usize) -> Self { + pub(crate) fn take_prefix(&mut self, n: usize) -> Self { let mid = if n <= self.len() { // SAFETY: We just checked that this will be between start and end, // and thus the addition cannot overflow. @@ -99,7 +99,7 @@ impl IndexRange { /// /// This is designed to help implement `Iterator::advance_back_by`. #[inline] - pub fn take_suffix(&mut self, n: usize) -> Self { + pub(crate) fn take_suffix(&mut self, n: usize) -> Self { let mid = if n <= self.len() { // SAFETY: We just checked that this will be between start and end, // and thus the subtraction cannot overflow. diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index cd444c86ed0..3ba2957526f 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -338,6 +338,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> { #[inline] #[track_caller] // because `Result::from_residual` has it #[lang = "from_yeet"] +#[allow(unreachable_pub)] // not-exposed but still used via lang-item pub fn from_yeet<T, Y>(yeeted: Y) -> T where T: FromResidual<Yeet<Y>>, @@ -383,12 +384,14 @@ impl<T> NeverShortCircuit<T> { /// This is useful for implementing infallible functions in terms of the `try_` ones, /// without accidentally capturing extra generic parameters in a closure. #[inline] - pub fn wrap_mut_1<A>(mut f: impl FnMut(A) -> T) -> impl FnMut(A) -> NeverShortCircuit<T> { + pub(crate) fn wrap_mut_1<A>( + mut f: impl FnMut(A) -> T, + ) -> impl FnMut(A) -> NeverShortCircuit<T> { move |a| NeverShortCircuit(f(a)) } #[inline] - pub fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self { + pub(crate) fn wrap_mut_2<A, B>(mut f: impl FnMut(A, B) -> T) -> impl FnMut(A, B) -> Self { move |a, b| NeverShortCircuit(f(a, b)) } } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 5a22110880c..ba5746d0ade 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3071,19 +3071,21 @@ impl<T> [T] { sort::unstable::sort(self, &mut |a, b| f(a).lt(&f(b))); } - /// Reorders the slice such that the element at `index` after the reordering is at its final - /// sorted position. + /// Reorders the slice such that the element at `index` is at a sort-order position. All + /// elements before `index` will be `<=` to this value, and all elements after will be `>=` to + /// it. /// - /// This reordering has the additional property that any value at position `i < index` will be - /// less than or equal to any value at a position `j > index`. Additionally, this reordering is - /// unstable (i.e. any number of equal elements may end up at position `index`), in-place (i.e. - /// does not allocate), and runs in *O*(*n*) time. This function is also known as "kth element" - /// in other libraries. + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// function is also known as "kth element" in other libraries. + /// + /// Returns a triple that partitions the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `x <= self[index]`. /// - /// It returns a triplet of the following from the reordered slice: the subslice prior to - /// `index`, the element at `index`, and the subslice after `index`; accordingly, the values in - /// those two subslices will respectively all be less-than-or-equal-to and - /// greater-than-or-equal-to the value of the element at `index`. + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `x >= self[index]`. /// /// # Current implementation /// @@ -3096,7 +3098,7 @@ impl<T> [T] { /// /// # Panics /// - /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// Panics when `index >= len()`, and so always panics on empty slices. /// /// May panic if the implementation of [`Ord`] for `T` does not implement a [total order]. /// @@ -3105,8 +3107,7 @@ impl<T> [T] { /// ``` /// let mut v = [-5i32, 4, 2, -3, 1]; /// - /// // Find the items less than or equal to the median, the median, and greater than or equal to - /// // the median. + /// // Find the items `<=` to the median, the median itself, and the items `>=` to it. /// let (lesser, median, greater) = v.select_nth_unstable(2); /// /// assert!(lesser == [-3, -5] || lesser == [-5, -3]); @@ -3132,19 +3133,23 @@ impl<T> [T] { sort::select::partition_at_index(self, index, T::lt) } - /// Reorders the slice with a comparator function such that the element at `index` after the - /// reordering is at its final sorted position. + /// Reorders the slice with a comparator function such that the element at `index` is at a + /// sort-order position. All elements before `index` will be `<=` to this value, and all + /// elements after will be `>=` to it, according to the comparator function. /// - /// This reordering has the additional property that any value at position `i < index` will be - /// less than or equal to any value at a position `j > index` using the comparator function. - /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This /// function is also known as "kth element" in other libraries. /// - /// It returns a triplet of the following from the slice reordered according to the provided - /// comparator function: the subslice prior to `index`, the element at `index`, and the subslice - /// after `index`; accordingly, the values in those two subslices will respectively all be - /// less-than-or-equal-to and greater-than-or-equal-to the value of the element at `index`. + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy + /// `compare(x, self[index]).is_le()`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy + /// `compare(x, self[index]).is_ge()`. /// /// # Current implementation /// @@ -3157,7 +3162,7 @@ impl<T> [T] { /// /// # Panics /// - /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// Panics when `index >= len()`, and so always panics on empty slices. /// /// May panic if `compare` does not implement a [total order]. /// @@ -3166,13 +3171,13 @@ impl<T> [T] { /// ``` /// let mut v = [-5i32, 4, 2, -3, 1]; /// - /// // Find the items less than or equal to the median, the median, and greater than or equal to - /// // the median as if the slice were sorted in descending order. - /// let (lesser, median, greater) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); + /// // Find the items `>=` to the median, the median itself, and the items `<=` to it, by using + /// // a reversed comparator. + /// let (before, median, after) = v.select_nth_unstable_by(2, |a, b| b.cmp(a)); /// - /// assert!(lesser == [4, 2] || lesser == [2, 4]); + /// assert!(before == [4, 2] || before == [2, 4]); /// assert_eq!(median, &mut 1); - /// assert!(greater == [-3, -5] || greater == [-5, -3]); + /// assert!(after == [-3, -5] || after == [-5, -3]); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -3197,19 +3202,21 @@ impl<T> [T] { sort::select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less) } - /// Reorders the slice with a key extraction function such that the element at `index` after the - /// reordering is at its final sorted position. + /// Reorders the slice with a key extraction function such that the element at `index` is at a + /// sort-order position. All elements before `index` will have keys `<=` to the key at `index`, + /// and all elements after will have keys `>=` to it. /// - /// This reordering has the additional property that any value at position `i < index` will be - /// less than or equal to any value at a position `j > index` using the key extraction function. - /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at - /// position `index`), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This + /// This reordering is unstable (i.e. any element that compares equal to the nth element may end + /// up at that position), in-place (i.e. does not allocate), and runs in *O*(*n*) time. This /// function is also known as "kth element" in other libraries. /// - /// It returns a triplet of the following from the slice reordered according to the provided key - /// extraction function: the subslice prior to `index`, the element at `index`, and the subslice - /// after `index`; accordingly, the values in those two subslices will respectively all be - /// less-than-or-equal-to and greater-than-or-equal-to the value of the element at `index`. + /// Returns a triple partitioning the reordered slice: + /// + /// * The unsorted subslice before `index`, whose elements all satisfy `f(x) <= f(self[index])`. + /// + /// * The element at `index`. + /// + /// * The unsorted subslice after `index`, whose elements all satisfy `f(x) >= f(self[index])`. /// /// # Current implementation /// @@ -3231,8 +3238,8 @@ impl<T> [T] { /// ``` /// let mut v = [-5i32, 4, 1, -3, 2]; /// - /// // Find the items less than or equal to the median, the median, and greater than or equal to - /// // the median as if the slice were sorted according to absolute value. + /// // Find the items `<=` to the absolute median, the absolute median itself, and the items + /// // `>=` to it. /// let (lesser, median, greater) = v.select_nth_unstable_by_key(2, |a| a.abs()); /// /// assert!(lesser == [1, 2] || lesser == [2, 1]); diff --git a/library/core/src/slice/rotate.rs b/library/core/src/slice/rotate.rs index 1e4865a7caa..d8e0acb565c 100644 --- a/library/core/src/slice/rotate.rs +++ b/library/core/src/slice/rotate.rs @@ -60,7 +60,7 @@ use crate::{cmp, ptr}; /// we cannot swap any more, but a smaller rotation problem is left to solve /// ``` /// when `left < right` the swapping happens from the left instead. -pub unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) { +pub(super) unsafe fn ptr_rotate<T>(mut left: usize, mut mid: *mut T, mut right: usize) { type BufType = [usize; 32]; if T::IS_ZST { return; diff --git a/library/core/src/unicode/mod.rs b/library/core/src/unicode/mod.rs index 6066aa99216..49dbdeb1a6d 100644 --- a/library/core/src/unicode/mod.rs +++ b/library/core/src/unicode/mod.rs @@ -17,6 +17,8 @@ pub(crate) use unicode_data::uppercase::lookup as Uppercase; pub(crate) use unicode_data::white_space::lookup as White_Space; pub(crate) mod printable; + +#[allow(unreachable_pub)] mod unicode_data; /// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of diff --git a/library/core/tests/bstr.rs b/library/core/tests/bstr.rs new file mode 100644 index 00000000000..5fecd0a4084 --- /dev/null +++ b/library/core/tests/bstr.rs @@ -0,0 +1,54 @@ +#![feature(bstr)] + +use core::ByteStr; + +#[test] +fn test_debug() { + assert_eq!( + r#""\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff""#, + format!("{:?}", ByteStr::new(b"\0\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x11\x12\r\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f \x7f\x80\x81\xfe\xff")), + ); +} + +#[test] +fn test_display() { + let b1 = ByteStr::new("abc"); + let b2 = ByteStr::new(b"\xf0\x28\x8c\xbc"); + + assert_eq!(&format!("{b1}"), "abc"); + assert_eq!(&format!("{b2}"), "�(��"); + + assert_eq!(&format!("{b1:<7}!"), "abc !"); + assert_eq!(&format!("{b1:>7}!"), " abc!"); + assert_eq!(&format!("{b1:^7}!"), " abc !"); + assert_eq!(&format!("{b1:^6}!"), " abc !"); + assert_eq!(&format!("{b1:-<7}!"), "abc----!"); + assert_eq!(&format!("{b1:->7}!"), "----abc!"); + assert_eq!(&format!("{b1:-^7}!"), "--abc--!"); + assert_eq!(&format!("{b1:-^6}!"), "-abc--!"); + + assert_eq!(&format!("{b2:<7}!"), "�(�� !"); + assert_eq!(&format!("{b2:>7}!"), " �(��!"); + assert_eq!(&format!("{b2:^7}!"), " �(�� !"); + assert_eq!(&format!("{b2:^6}!"), " �(�� !"); + assert_eq!(&format!("{b2:-<7}!"), "�(��---!"); + assert_eq!(&format!("{b2:->7}!"), "---�(��!"); + assert_eq!(&format!("{b2:-^7}!"), "-�(��--!"); + assert_eq!(&format!("{b2:-^6}!"), "-�(��-!"); + + assert_eq!(&format!("{b1:<2}!"), "abc!"); + assert_eq!(&format!("{b1:>2}!"), "abc!"); + assert_eq!(&format!("{b1:^2}!"), "abc!"); + assert_eq!(&format!("{b1:-<2}!"), "abc!"); + assert_eq!(&format!("{b1:->2}!"), "abc!"); + assert_eq!(&format!("{b1:-^2}!"), "abc!"); + + assert_eq!(&format!("{b2:<3}!"), "�(��!"); + assert_eq!(&format!("{b2:>3}!"), "�(��!"); + assert_eq!(&format!("{b2:^3}!"), "�(��!"); + assert_eq!(&format!("{b2:^2}!"), "�(��!"); + assert_eq!(&format!("{b2:-<3}!"), "�(��!"); + assert_eq!(&format!("{b2:->3}!"), "�(��!"); + assert_eq!(&format!("{b2:-^3}!"), "�(��!"); + assert_eq!(&format!("{b2:-^2}!"), "�(��!"); +} diff --git a/library/core/tests/net/ip_addr.rs b/library/core/tests/net/ip_addr.rs index 707f9a160e1..f01b43282ec 100644 --- a/library/core/tests/net/ip_addr.rs +++ b/library/core/tests/net/ip_addr.rs @@ -332,6 +332,7 @@ fn ip_properties() { check!("ff08::", global | multicast); check!("ff0e::", global | multicast); check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff", doc); check!("2001:2::ac32:23ff:21", benchmarking); check!("102:304:506:708:90a:b0c:d0e:f10", global); } @@ -791,6 +792,15 @@ fn ipv6_properties() { ); check!( + "3fff:fff:ffff:ffff:ffff:ffff:ffff:ffff", + &[ + 0x3f, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + documentation + ); + + check!( "2001:2::ac32:23ff:21", &[0x20, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0xac, 0x32, 0x23, 0xff, 0, 0x21], benchmarking diff --git a/library/panic_unwind/src/dummy.rs b/library/panic_unwind/src/dummy.rs index a4bcd216c60..a0d68766918 100644 --- a/library/panic_unwind/src/dummy.rs +++ b/library/panic_unwind/src/dummy.rs @@ -6,10 +6,10 @@ use alloc::boxed::Box; use core::any::Any; use core::intrinsics; -pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> { +pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> { intrinsics::abort() } -pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 { +pub(crate) unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 { intrinsics::abort() } diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs index b986fc1c2a8..9127449edb1 100644 --- a/library/panic_unwind/src/emcc.rs +++ b/library/panic_unwind/src/emcc.rs @@ -64,7 +64,7 @@ struct Exception { data: Option<Box<dyn Any + Send>>, } -pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> { +pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> { // intrinsics::try actually gives us a pointer to this structure. #[repr(C)] struct CatchData { @@ -93,7 +93,7 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> { out } -pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { +pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { let exception = __cxa_allocate_exception(mem::size_of::<Exception>()) as *mut Exception; if exception.is_null() { return uw::_URC_FATAL_PHASE1_ERROR as u32; diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index b2389078afd..e478f6c5fc8 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -58,7 +58,7 @@ struct Exception { cause: Box<dyn Any + Send>, } -pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { +pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { let exception = Box::new(Exception { _uwe: uw::_Unwind_Exception { exception_class: RUST_EXCEPTION_CLASS, @@ -82,7 +82,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { } } -pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> { +pub(crate) unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> { let exception = ptr as *mut uw::_Unwind_Exception; if (*exception).exception_class != RUST_EXCEPTION_CLASS { uw::_Unwind_DeleteException(exception); diff --git a/library/panic_unwind/src/hermit.rs b/library/panic_unwind/src/hermit.rs index 69b9edb77c5..8ac827dd9cc 100644 --- a/library/panic_unwind/src/hermit.rs +++ b/library/panic_unwind/src/hermit.rs @@ -5,14 +5,14 @@ use alloc::boxed::Box; use core::any::Any; -pub unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> { +pub(crate) unsafe fn cleanup(_ptr: *mut u8) -> Box<dyn Any + Send> { extern "C" { pub fn __rust_abort() -> !; } __rust_abort(); } -pub unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 { +pub(crate) unsafe fn panic(_data: Box<dyn Any + Send>) -> u32 { extern "C" { pub fn __rust_abort() -> !; } diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index dc78be76cb4..d6828164195 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -26,6 +26,7 @@ #![cfg_attr(miri, allow(dead_code))] #![allow(internal_features)] #![cfg_attr(not(bootstrap), feature(cfg_emscripten_wasm_eh))] +#![warn(unreachable_pub)] use alloc::boxed::Box; use core::any::Any; diff --git a/library/panic_unwind/src/miri.rs b/library/panic_unwind/src/miri.rs index 695adadd59b..a86f0e91eef 100644 --- a/library/panic_unwind/src/miri.rs +++ b/library/panic_unwind/src/miri.rs @@ -12,14 +12,14 @@ extern "Rust" { fn miri_start_unwind(payload: *mut u8) -> !; } -pub unsafe fn panic(payload: Box<dyn Any + Send>) -> u32 { +pub(crate) unsafe fn panic(payload: Box<dyn Any + Send>) -> u32 { // The payload we pass to `miri_start_unwind` will be exactly the argument we get // in `cleanup` below. So we just box it up once, to get something pointer-sized. let payload_box: Payload = Box::new(payload); miri_start_unwind(Box::into_raw(payload_box) as *mut u8) } -pub unsafe fn cleanup(payload_box: *mut u8) -> Box<dyn Any + Send> { +pub(crate) unsafe fn cleanup(payload_box: *mut u8) -> Box<dyn Any + Send> { // Recover the underlying `Box`. let payload_box: Payload = Box::from_raw(payload_box as *mut _); *payload_box diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 5afa0a19756..21bfe74e1a2 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -111,18 +111,18 @@ struct Exception { mod imp { #[repr(transparent)] #[derive(Copy, Clone)] - pub struct ptr_t(*mut u8); + pub(super) struct ptr_t(*mut u8); impl ptr_t { - pub const fn null() -> Self { + pub(super) const fn null() -> Self { Self(core::ptr::null_mut()) } - pub const fn new(ptr: *mut u8) -> Self { + pub(super) const fn new(ptr: *mut u8) -> Self { Self(ptr) } - pub const fn raw(self) -> *mut u8 { + pub(super) const fn raw(self) -> *mut u8 { self.0 } } @@ -133,18 +133,18 @@ mod imp { // On 64-bit systems, SEH represents pointers as 32-bit offsets from `__ImageBase`. #[repr(transparent)] #[derive(Copy, Clone)] - pub struct ptr_t(u32); + pub(super) struct ptr_t(u32); extern "C" { - pub static __ImageBase: u8; + static __ImageBase: u8; } impl ptr_t { - pub const fn null() -> Self { + pub(super) const fn null() -> Self { Self(0) } - pub fn new(ptr: *mut u8) -> Self { + pub(super) fn new(ptr: *mut u8) -> Self { // We need to expose the provenance of the pointer because it is not carried by // the `u32`, while the FFI needs to have this provenance to excess our statics. // @@ -159,7 +159,7 @@ mod imp { Self(offset as u32) } - pub const fn raw(self) -> u32 { + pub(super) const fn raw(self) -> u32 { self.0 } } @@ -168,7 +168,7 @@ mod imp { use imp::ptr_t; #[repr(C)] -pub struct _ThrowInfo { +struct _ThrowInfo { pub attributes: c_uint, pub pmfnUnwind: ptr_t, pub pForwardCompat: ptr_t, @@ -176,13 +176,13 @@ pub struct _ThrowInfo { } #[repr(C)] -pub struct _CatchableTypeArray { +struct _CatchableTypeArray { pub nCatchableTypes: c_int, pub arrayOfCatchableTypes: [ptr_t; 1], } #[repr(C)] -pub struct _CatchableType { +struct _CatchableType { pub properties: c_uint, pub pType: ptr_t, pub thisDisplacement: _PMD, @@ -191,14 +191,14 @@ pub struct _CatchableType { } #[repr(C)] -pub struct _PMD { +struct _PMD { pub mdisp: c_int, pub pdisp: c_int, pub vdisp: c_int, } #[repr(C)] -pub struct _TypeDescriptor { +struct _TypeDescriptor { pub pVFTable: *const u8, pub spare: *mut u8, pub name: [u8; 11], @@ -288,7 +288,7 @@ cfg_if::cfg_if! { } } -pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { +pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { use core::intrinsics::atomic_store_seqcst; // _CxxThrowException executes entirely on this stack frame, so there's no @@ -350,7 +350,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { _CxxThrowException(throw_ptr, (&raw mut THROW_INFO) as *mut _); } -pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> { +pub(crate) unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> { // A null payload here means that we got here from the catch (...) of // __rust_try. This happens when a non-Rust foreign exception is caught. if payload.is_null() { diff --git a/library/rtstartup/rsbegin.rs b/library/rtstartup/rsbegin.rs index 9a3d95bd8dd..d3ff5c14aa4 100644 --- a/library/rtstartup/rsbegin.rs +++ b/library/rtstartup/rsbegin.rs @@ -19,6 +19,7 @@ #![no_core] #![allow(non_camel_case_types)] #![allow(internal_features)] +#![warn(unreachable_pub)] #[lang = "sized"] trait Sized {} diff --git a/library/rtstartup/rsend.rs b/library/rtstartup/rsend.rs index 2514eb00344..81acfbed447 100644 --- a/library/rtstartup/rsend.rs +++ b/library/rtstartup/rsend.rs @@ -6,6 +6,7 @@ #![crate_type = "rlib"] #![no_core] #![allow(internal_features)] +#![warn(unreachable_pub)] #[lang = "sized"] trait Sized {} diff --git a/library/std/src/bstr.rs b/library/std/src/bstr.rs new file mode 100644 index 00000000000..dd491771628 --- /dev/null +++ b/library/std/src/bstr.rs @@ -0,0 +1,4 @@ +//! The `ByteStr` and `ByteString` types and trait implementations. + +#[unstable(feature = "bstr", issue = "134915")] +pub use alloc::bstr::{ByteStr, ByteString}; diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 11a29cdae62..bbd506127fb 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -336,7 +336,10 @@ impl Error for VarError { /// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188) /// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) /// +/// To pass an environment variable to a child process, you can instead use [`Command::env`]. +/// /// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs +/// [`Command::env`]: crate::process::Command::env /// /// # Panics /// @@ -396,7 +399,12 @@ pub unsafe fn set_var<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) { /// - [Austin Group Bugzilla](https://austingroupbugs.net/view.php?id=188) /// - [GNU C library Bugzilla](https://sourceware.org/bugzilla/show_bug.cgi?id=15607#c2) /// +/// To prevent a child process from inheriting an environment variable, you can +/// instead use [`Command::env_remove`] or [`Command::env_clear`]. +/// /// [`std::net::ToSocketAddrs`]: crate::net::ToSocketAddrs +/// [`Command::env_remove`]: crate::process::Command::env_remove +/// [`Command::env_clear`]: crate::process::Command::env_clear /// /// # Panics /// diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 7fb57d41043..c4c8dbccd7a 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -203,8 +203,8 @@ impl OsString { self } - /// Converts the `OsString` into a byte slice. To convert the byte slice back into an - /// `OsString`, use the [`OsStr::from_encoded_bytes_unchecked`] function. + /// Converts the `OsString` into a byte vector. To convert the byte vector back into an + /// `OsString`, use the [`OsString::from_encoded_bytes_unchecked`] function. /// /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 0c526eafdf3..1d26bf37f4d 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -2387,13 +2387,12 @@ mod async_keyword {} /// [`async`]: ../std/keyword.async.html mod await_keyword {} -// FIXME(dyn_compat_renaming): Update URL and link text. #[doc(keyword = "dyn")] // /// `dyn` is a prefix of a [trait object]'s type. /// /// The `dyn` keyword is used to highlight that calls to methods on the associated `Trait` -/// are [dynamically dispatched]. To use the trait this way, it must be 'dyn-compatible'[^1]. +/// are [dynamically dispatched]. To use the trait this way, it must be *dyn compatible*[^1]. /// /// Unlike generic parameters or `impl Trait`, the compiler does not know the concrete type that /// is being passed. That is, the type has been [erased]. @@ -2406,7 +2405,7 @@ mod await_keyword {} /// the function pointer and then that function pointer is called. /// /// See the Reference for more information on [trait objects][ref-trait-obj] -/// and [object safety][ref-obj-safety]. +/// and [dyn compatibility][ref-dyn-compat]. /// /// ## Trade-offs /// @@ -2419,9 +2418,9 @@ mod await_keyword {} /// [trait object]: ../book/ch17-02-trait-objects.html /// [dynamically dispatched]: https://en.wikipedia.org/wiki/Dynamic_dispatch /// [ref-trait-obj]: ../reference/types/trait-object.html -/// [ref-obj-safety]: ../reference/items/traits.html#object-safety +/// [ref-dyn-compat]: ../reference/items/traits.html#dyn-compatibility /// [erased]: https://en.wikipedia.org/wiki/Type_erasure -/// [^1]: Formerly known as 'object safe'. +/// [^1]: Formerly known as *object safe*. mod dyn_keyword {} #[doc(keyword = "union")] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 39f234e4ba6..acb3a0578e5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -320,6 +320,8 @@ // Library features (core): // tidy-alphabetical-start #![feature(array_chunks)] +#![feature(bstr)] +#![feature(bstr_internals)] #![feature(c_str_module)] #![feature(char_internals)] #![feature(clone_to_uninit)] @@ -581,6 +583,8 @@ pub mod f64; pub mod thread; pub mod ascii; pub mod backtrace; +#[unstable(feature = "bstr", issue = "134915")] +pub mod bstr; pub mod collections; pub mod env; pub mod error; diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs index 22f5528248a..03dff94350d 100644 --- a/library/std/src/os/fd/raw.rs +++ b/library/std/src/os/fd/raw.rs @@ -19,11 +19,9 @@ use crate::sys_common::{AsInner, IntoInner}; use crate::{fs, io}; /// Raw file descriptors. -#[rustc_allowed_through_unstable_modules] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(not(target_os = "hermit"))] pub type RawFd = raw::c_int; -#[rustc_allowed_through_unstable_modules] #[stable(feature = "rust1", since = "1.0.0")] #[cfg(target_os = "hermit")] pub type RawFd = i32; @@ -33,7 +31,6 @@ pub type RawFd = i32; /// This is only available on unix and WASI platforms and must be imported in /// order to call the method. Windows platforms have a corresponding /// `AsRawHandle` and `AsRawSocket` set of traits. -#[rustc_allowed_through_unstable_modules] #[stable(feature = "rust1", since = "1.0.0")] pub trait AsRawFd { /// Extracts the raw file descriptor. @@ -67,7 +64,6 @@ pub trait AsRawFd { /// A trait to express the ability to construct an object from a raw file /// descriptor. -#[rustc_allowed_through_unstable_modules] #[stable(feature = "from_raw_os", since = "1.1.0")] pub trait FromRawFd { /// Constructs a new instance of `Self` from the given raw file @@ -112,7 +108,6 @@ pub trait FromRawFd { /// A trait to express the ability to consume an object and acquire ownership of /// its raw file descriptor. -#[rustc_allowed_through_unstable_modules] #[stable(feature = "into_raw_os", since = "1.4.0")] pub trait IntoRawFd { /// Consumes this object, returning the raw underlying file descriptor. diff --git a/library/std/src/os/wasi/io/fd.rs b/library/std/src/os/wasi/io/fd.rs deleted file mode 100644 index 930aca887e3..00000000000 --- a/library/std/src/os/wasi/io/fd.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Owned and borrowed file descriptors. - -#![unstable(feature = "wasi_ext", issue = "71213")] - -// Tests for this module -#[cfg(test)] -mod tests; - -pub use crate::os::fd::owned::*; diff --git a/library/std/src/os/wasi/io/mod.rs b/library/std/src/os/wasi/io/mod.rs index 4e123a1eec8..5f9a735db08 100644 --- a/library/std/src/os/wasi/io/mod.rs +++ b/library/std/src/os/wasi/io/mod.rs @@ -4,3 +4,7 @@ #[stable(feature = "io_safety_wasi", since = "1.65.0")] pub use crate::os::fd::*; + +// Tests for this module +#[cfg(test)] +mod tests; diff --git a/library/std/src/os/wasi/io/raw.rs b/library/std/src/os/wasi/io/raw.rs deleted file mode 100644 index da3b36adad4..00000000000 --- a/library/std/src/os/wasi/io/raw.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! WASI-specific extensions to general I/O primitives. - -#![unstable(feature = "wasi_ext", issue = "71213")] - -// NOTE: despite the fact that this module is unstable, -// stable Rust had the capability to access the stable -// re-exported items from os::fd::raw through this -// unstable module. -// In PR #95956 the stability checker was changed to check -// all path segments of an item rather than just the last, -// which caused the aforementioned stable usage to regress -// (see issue #99502). -// As a result, the items in os::fd::raw were given the -// rustc_allowed_through_unstable_modules attribute. -// No regression tests were added to ensure this property, -// as CI is not configured to test wasm32-wasi. -// If this module is stabilized, -// you may want to remove those attributes -// (assuming no other unstable modules need them). -pub use crate::os::fd::raw::*; diff --git a/library/std/src/os/wasi/io/fd/tests.rs b/library/std/src/os/wasi/io/tests.rs index 418274752b0..418274752b0 100644 --- a/library/std/src/os/wasi/io/fd/tests.rs +++ b/library/std/src/os/wasi/io/tests.rs diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 384369b0012..3a22a16cb16 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -32,9 +32,14 @@ use crate::{mem, panic, sys}; // - nothing (so this macro is a no-op) macro_rules! rtprintpanic { ($($t:tt)*) => { + #[cfg(not(feature = "panic_immediate_abort"))] if let Some(mut out) = crate::sys::stdio::panic_output() { let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); } + #[cfg(feature = "panic_immediate_abort")] + { + let _ = format_args!($($t)*); + } } } diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index b3659351b8c..f8493c21ad4 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -328,9 +328,6 @@ impl File { mem::size_of::<c::FILE_ALLOCATION_INFO>() as u32, ); if result == 0 { - if api::get_last_error().code != 0 { - panic!("FILE_ALLOCATION_INFO failed!!!"); - } let eof = c::FILE_END_OF_FILE_INFO { EndOfFile: 0 }; let result = c::SetFileInformationByHandle( handle.as_raw_handle(), diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 2313f4b5beb..c003503ca8b 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -230,6 +230,14 @@ impl fmt::Display for AccessError { #[stable(feature = "thread_local_try_with", since = "1.26.0")] impl Error for AccessError {} +// This ensures the panicking code is outlined from `with` for `LocalKey`. +#[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] +#[track_caller] +#[cold] +fn panic_access_error(err: AccessError) -> ! { + panic!("cannot access a Thread Local Storage value during or after destruction: {err:?}") +} + impl<T: 'static> LocalKey<T> { #[doc(hidden)] #[unstable( @@ -269,10 +277,10 @@ impl<T: 'static> LocalKey<T> { where F: FnOnce(&T) -> R, { - self.try_with(f).expect( - "cannot access a Thread Local Storage value \ - during or after destruction", - ) + match self.try_with(f) { + Ok(r) => r, + Err(err) => panic_access_error(err), + } } /// Acquires a reference to the value in this TLS key. @@ -327,10 +335,10 @@ impl<T: 'static> LocalKey<T> { let mut init = Some(init); let reference = unsafe { - (self.inner)(Some(&mut init)).as_ref().expect( - "cannot access a Thread Local Storage value \ - during or after destruction", - ) + match (self.inner)(Some(&mut init)).as_ref() { + Some(r) => r, + None => panic_access_error(AccessError), + } }; f(init, reference) diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index c46aae2ded1..d2f3c7f36ca 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -62,7 +62,7 @@ dependencies = [ "tracing-subscriber", "tracing-tree", "walkdir", - "windows 0.52.0", + "windows", "xz2", ] @@ -663,7 +663,7 @@ dependencies = [ "libc", "memchr", "ntapi", - "windows 0.57.0", + "windows", ] [[package]] @@ -845,30 +845,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" -dependencies = [ - "windows-core 0.52.0", - "windows-targets", -] - -[[package]] -name = "windows" version = "0.57.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" dependencies = [ - "windows-core 0.57.0", - "windows-targets", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ + "windows-core", "windows-targets", ] diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 71c56c4e85e..d7afcc7f27d 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -74,7 +74,7 @@ tracing-tree = { version = "0.4.0", optional = true } version = "1.0.0" [target.'cfg(windows)'.dependencies.windows] -version = "0.52" +version = "0.57" features = [ "Win32_Foundation", "Win32_Security", diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 76ee40c6f45..74923af1555 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1268,6 +1268,11 @@ def bootstrap(args): config_toml = "" profile = RustBuild.get_toml_static(config_toml, "profile") + is_non_git_source = not os.path.exists(os.path.join(rust_root, ".git")) + + if profile is None and is_non_git_source: + profile = "dist" + if profile is not None: # Allows creating alias for profile names, allowing # profiles to be renamed while maintaining back compatibility diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml index a737de3bd08..269b90106e3 100644 --- a/src/bootstrap/defaults/config.compiler.toml +++ b/src/bootstrap/defaults/config.compiler.toml @@ -8,6 +8,8 @@ compiler-docs = true # where adding `debug!()` appears to do nothing. # However, it makes running the compiler slightly slower. debug-logging = true +# Enables debug assertions, which guard from many mistakes when working on the compiler. +debug-assertions = true # Get actually-useful information from backtraces, profiling, etc. with minimal added bytes debuginfo-level = "line-tables-only" # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index a1f38b9ac14..275c0e803cb 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -97,13 +97,18 @@ tidy: prepare: $(Q)$(BOOTSTRAP) build --stage 2 --dry-run +# Set of tests that represent around half of the time of the test suite. +# Used to split tests across multiple CI runners. +STAGE_2_TEST_SET1 := test --stage 2 --skip=compiler --skip=src +STAGE_2_TEST_SET2 := test --stage 2 --skip=tests --skip=coverage-map --skip=coverage-run --skip=library --skip=tidyselftest + ## MSVC native builders # this intentionally doesn't use `$(BOOTSTRAP)` so we can test the shebang on Windows ci-msvc-py: - $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 tidy + $(Q)$(CFG_SRC_DIR)/x.py $(STAGE_2_TEST_SET1) ci-msvc-ps1: - $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 --skip tidy + $(Q)$(CFG_SRC_DIR)/x.ps1 $(STAGE_2_TEST_SET2) ci-msvc: ci-msvc-py ci-msvc-ps1 ## MingW native builders @@ -112,9 +117,9 @@ ci-msvc: ci-msvc-py ci-msvc-ps1 # Used to split tests across multiple CI runners. # Test both x and bootstrap entrypoints. ci-mingw-x: - $(Q)$(CFG_SRC_DIR)/x test --stage 2 --skip=compiler --skip=src + $(Q)$(CFG_SRC_DIR)/x $(STAGE_2_TEST_SET1) ci-mingw-bootstrap: - $(Q)$(BOOTSTRAP) test --stage 2 --skip=tests --skip=coverage-map --skip=coverage-run --skip=library --skip=tidyselftest + $(Q)$(BOOTSTRAP) $(STAGE_2_TEST_SET2) ci-mingw: ci-mingw-x ci-mingw-bootstrap .PHONY: dist diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 470e400243f..18f920b85ee 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1015,7 +1015,18 @@ impl Step for PlainSourceTarball { ]; let src_dirs = ["src", "compiler", "library", "tests", "LICENSES"]; - copy_src_dirs(builder, &builder.src, &src_dirs, &[], plain_dst_src); + copy_src_dirs( + builder, + &builder.src, + &src_dirs, + &[ + // We don't currently use the GCC source code for building any official components, + // it is very big, and has unclear licensing implications due to being GPL licensed. + // We thus exclude it from the source tarball from now. + "src/gcc", + ], + plain_dst_src, + ); // Copy the files normally for item in &src_files { diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index cf55fff4078..3cf25373b89 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1338,7 +1338,7 @@ impl Step for CrtBeginEnd { .file(crtbegin_src) .file(crtend_src); - // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt + // Those flags are defined in src/llvm-project/compiler-rt/lib/builtins/CMakeLists.txt // Currently only consumer of those objects is musl, which use .init_array/.fini_array // instead of .ctors/.dtors cfg.flag("-std=c11") diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 9f3e4d9cc89..0d3ab6ad97d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -87,7 +87,7 @@ impl Step for CrateBootstrap { &[], ); let crate_name = path.rsplit_once('/').unwrap().1; - run_cargo_test(cargo, &[], &[], crate_name, crate_name, compiler, bootstrap_host, builder); + run_cargo_test(cargo, &[], &[], crate_name, crate_name, bootstrap_host, builder); } } @@ -143,7 +143,6 @@ You can skip linkcheck with --skip src/tools/linkchecker" &[], "linkchecker", "linkchecker self tests", - compiler, bootstrap_host, builder, ); @@ -312,7 +311,7 @@ impl Step for Cargo { ); // NOTE: can't use `run_cargo_test` because we need to overwrite `PATH` - let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", compiler, self.host, builder); + let mut cargo = prepare_cargo_test(cargo, &[], &[], "cargo", self.host, builder); // Don't run cross-compile tests, we may not have cross-compiled libstd libs // available. @@ -397,7 +396,7 @@ impl Step for RustAnalyzer { cargo.env("SKIP_SLOW_TESTS", "1"); cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", compiler, host, builder); + run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", host, builder); } } @@ -445,7 +444,7 @@ impl Step for Rustfmt { cargo.add_rustc_lib_path(builder); - run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", compiler, host, builder); + run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", host, builder); } } @@ -565,7 +564,7 @@ impl Step for Miri { // We can NOT use `run_cargo_test` since Miri's integration tests do not use the usual test // harness and therefore do not understand the flags added by `add_flags_and_try_run_test`. - let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host_compiler, host, builder); + let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", host, builder); // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", &miri_sysroot); @@ -713,16 +712,7 @@ impl Step for CompiletestTest { &[], ); cargo.allow_features("test"); - run_cargo_test( - cargo, - &[], - &[], - "compiletest", - "compiletest self test", - compiler, - host, - builder, - ); + run_cargo_test(cargo, &[], &[], "compiletest", "compiletest self test", host, builder); } } @@ -769,7 +759,7 @@ impl Step for Clippy { cargo.env("HOST_LIBS", host_libs); cargo.add_rustc_lib_path(builder); - let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder); + let cargo = prepare_cargo_test(cargo, &[], &[], "clippy", host, builder); let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host); @@ -1294,7 +1284,6 @@ impl Step for CrateRunMakeSupport { &[], "run-make-support", "run-make-support self test", - compiler, host, builder, ); @@ -1334,16 +1323,7 @@ impl Step for CrateBuildHelper { &[], ); cargo.allow_features("test"); - run_cargo_test( - cargo, - &[], - &[], - "build_helper", - "build_helper self test", - compiler, - host, - builder, - ); + run_cargo_test(cargo, &[], &[], "build_helper", "build_helper self test", host, builder); } } @@ -2540,19 +2520,17 @@ impl Step for CrateLibrustc { /// Given a `cargo test` subcommand, add the appropriate flags and run it. /// /// Returns whether the test succeeded. -#[allow(clippy::too_many_arguments)] // FIXME: reduce the number of args and remove this. fn run_cargo_test<'a>( - cargo: impl Into<BootstrapCommand>, + cargo: builder::Cargo, libtest_args: &[&str], crates: &[String], primary_crate: &str, description: impl Into<Option<&'a str>>, - compiler: Compiler, target: TargetSelection, builder: &Builder<'_>, ) -> bool { - let mut cargo = - prepare_cargo_test(cargo, libtest_args, crates, primary_crate, compiler, target, builder); + let compiler = cargo.compiler(); + let mut cargo = prepare_cargo_test(cargo, libtest_args, crates, primary_crate, target, builder); let _time = helpers::timeit(builder); let _group = description.into().and_then(|what| { builder.msg_sysroot_tool(Kind::Test, compiler.stage, what, compiler.host, target) @@ -2573,15 +2551,15 @@ fn run_cargo_test<'a>( /// Given a `cargo test` subcommand, pass it the appropriate test flags given a `builder`. fn prepare_cargo_test( - cargo: impl Into<BootstrapCommand>, + cargo: builder::Cargo, libtest_args: &[&str], crates: &[String], primary_crate: &str, - compiler: Compiler, target: TargetSelection, builder: &Builder<'_>, ) -> BootstrapCommand { - let mut cargo = cargo.into(); + let compiler = cargo.compiler(); + let mut cargo: BootstrapCommand = cargo.into(); // Propagate `--bless` if it has not already been set/unset // Any tools that want to use this should bless if `RUSTC_BLESS` is set to @@ -2793,7 +2771,6 @@ impl Step for Crate { &self.crates, &self.crates[0], &*crate_description(&self.crates), - compiler, target, builder, ); @@ -2895,7 +2872,6 @@ impl Step for CrateRustdoc { &["rustdoc:0.0.0".to_string()], "rustdoc", "rustdoc", - compiler, target, builder, ); @@ -2956,7 +2932,6 @@ impl Step for CrateRustdocJsonTypes { &["rustdoc-json-types".to_string()], "rustdoc-json-types", "rustdoc-json-types", - compiler, target, builder, ); @@ -3113,23 +3088,25 @@ impl Step for Bootstrap { // Use `python -m unittest` manually if you want to pass arguments. check_bootstrap.delay_failure().run(builder); - let mut cmd = command(&builder.initial_cargo); - cmd.arg("test") - .current_dir(builder.src.join("src/bootstrap")) - .env("RUSTFLAGS", "--cfg test -Cdebuginfo=2") + let mut cargo = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolBootstrap, + host, + Kind::Test, + "src/bootstrap", + SourceType::InTree, + &[], + ); + + cargo + .rustflag("-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) - .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTDOC", builder.rustdoc(compiler)) - .env("RUSTC", &builder.initial_rustc); - if let Some(flags) = option_env!("RUSTFLAGS") { - // Use the same rustc flags for testing as for "normal" compilation, - // so that Cargo doesn’t recompile the entire dependency graph every time: - // https://github.com/rust-lang/rust/issues/49215 - cmd.env("RUSTFLAGS", flags); - } + .env("RUSTC_BOOTSTRAP", "1"); + // bootstrap tests are racy on directory creation so just run them one at a time. // Since there's not many this shouldn't be a problem. - run_cargo_test(cmd, &["--test-threads=1"], &[], "bootstrap", None, compiler, host, builder); + run_cargo_test(cargo, &["--test-threads=1"], &[], "bootstrap", None, host, builder); } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { @@ -3254,7 +3231,7 @@ impl Step for RustInstaller { bootstrap_host, bootstrap_host, ); - run_cargo_test(cargo, &[], &[], "installer", None, compiler, bootstrap_host, builder); + run_cargo_test(cargo, &[], &[], "installer", None, bootstrap_host, builder); // We currently don't support running the test.sh script outside linux(?) environments. // Eventually this should likely migrate to #[test]s in rust-installer proper rather than a @@ -3639,16 +3616,7 @@ impl Step for TestFloatParse { &[], ); - run_cargo_test( - cargo_test, - &[], - &[], - crate_name, - crate_name, - compiler, - bootstrap_host, - builder, - ); + run_cargo_test(cargo_test, &[], &[], crate_name, crate_name, bootstrap_host, builder); // Run the actual parse tests. let mut cargo_run = tool::prepare_tool_cargo( diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index f9fb19ddb09..6b792108784 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -121,6 +121,10 @@ impl Cargo { cargo } + pub fn compiler(&self) -> Compiler { + self.compiler + } + pub fn into_cmd(self) -> BootstrapCommand { self.into() } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 1c49063ef5c..910550b0a7d 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -2875,21 +2875,26 @@ impl Config { allowed_paths.push(":!library"); } - // Look for a version to compare to based on the current commit. - // Only commits merged by bors will have CI artifacts. - let commit = match self.last_modified_commit(&allowed_paths, "download-rustc", if_unchanged) - { - Some(commit) => commit, - None => { - if if_unchanged { - return None; + let commit = if self.rust_info.is_managed_git_subrepository() { + // Look for a version to compare to based on the current commit. + // Only commits merged by bors will have CI artifacts. + match self.last_modified_commit(&allowed_paths, "download-rustc", if_unchanged) { + Some(commit) => commit, + None => { + if if_unchanged { + return None; + } + println!("ERROR: could not find commit hash for downloading rustc"); + println!("HELP: maybe your repository history is too shallow?"); + println!("HELP: consider setting `rust.download-rustc=false` in config.toml"); + println!("HELP: or fetch enough history to include one upstream commit"); + crate::exit!(1); } - println!("ERROR: could not find commit hash for downloading rustc"); - println!("HELP: maybe your repository history is too shallow?"); - println!("HELP: consider setting `rust.download-rustc=false` in config.toml"); - println!("HELP: or fetch enough history to include one upstream commit"); - crate::exit!(1); } + } else { + channel::read_commit_info_file(&self.src) + .map(|info| info.sha.trim().to_owned()) + .expect("git-commit-info is missing in the project root") }; if CiEnv::is_ci() && { @@ -2926,10 +2931,8 @@ impl Config { let if_unchanged = || { if self.rust_info.is_from_tarball() { // Git is needed for running "if-unchanged" logic. - println!( - "WARNING: 'if-unchanged' has no effect on tarball sources; ignoring `download-ci-llvm`." - ); - return false; + println!("ERROR: 'if-unchanged' is only compatible with Git managed sources."); + crate::exit!(1); } // Fetching the LLVM submodule is unnecessary for self-tests. @@ -2971,6 +2974,11 @@ impl Config { option_name: &str, if_unchanged: bool, ) -> Option<String> { + assert!( + self.rust_info.is_managed_git_subrepository(), + "Can't run `Config::last_modified_commit` on a non-git source." + ); + // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap(); diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs index c5e578ff351..f0a185ee3a7 100644 --- a/src/bootstrap/src/core/config/tests.rs +++ b/src/bootstrap/src/core/config/tests.rs @@ -92,7 +92,7 @@ fn detect_src_and_out() { // `{build-dir}/bootstrap/debug/deps/bootstrap-c7ee91d5661e2804` // `{build-dir}` can be anywhere, not just in the rust project directory. let dep = Path::new(args.first().unwrap()); - let expected_out = dep.ancestors().nth(4).unwrap(); + let expected_out = dep.ancestors().nth(5).unwrap(); assert_eq!(&cfg.out, expected_out); } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 85d17c8fa50..a3eb781f147 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -335,4 +335,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "Some stamp names in the build artifacts may have changed slightly (e.g., from `llvm-finished-building` to `.llvm-stamp`).", }, + ChangeInfo { + change_id: 135729, + severity: ChangeSeverity::Info, + summary: "Change the compiler profile to default to rust.debug-assertions = true", + }, ]; diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 2f52ff5a99a..2b1de43c2f6 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -305,8 +305,6 @@ For targets: `mips-unknown-linux-gnu` - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} - Path and misc options > Use a mirror = ENABLE - Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc -- Path and misc options > Patches origin = Bundled, then local -- Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = mips - Target options > ABI = o32 - Target options > Endianness = Big endian @@ -327,8 +325,6 @@ For targets: `mipsel-unknown-linux-gnu` - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} - Path and misc options > Use a mirror = ENABLE - Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc -- Path and misc options > Patches origin = Bundled, then local -- Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = mips - Target options > ABI = o32 - Target options > Endianness = Little endian @@ -349,8 +345,6 @@ For targets: `mips64-unknown-linux-gnuabi64` - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} - Path and misc options > Use a mirror = ENABLE - Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc -- Path and misc options > Patches origin = Bundled, then local -- Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = mips - Target options > ABI = n64 - Target options > Endianness = Big endian @@ -370,8 +364,6 @@ For targets: `mips64el-unknown-linux-gnuabi64` - Path and misc options > Prefix directory = /x-tools/${CT\_TARGET} - Path and misc options > Use a mirror = ENABLE - Path and misc options > Base URL = https://ci-mirrors.rust-lang.org/rustc -- Path and misc options > Patches origin = Bundled, then local -- Path and misc options > Local patch directory = /tmp/patches - Target options > Target Architecture = mips - Target options > ABI = n64 - Target options > Endianness = Little endian diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile index c08febf423a..4a090dcdd50 100644 --- a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile @@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/ COPY host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig index 75743fe8141..94db07922a2 100644 --- a/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-mips-linux/mips-linux-gnu.defconfig @@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4" CT_PREFIX_DIR="/x-tools/${CT_TARGET}" CT_USE_MIRROR=y CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" -CT_PATCH_BUNDLED_LOCAL=y -CT_LOCAL_PATCH_DIR="/tmp/patches" CT_ARCH_MIPS=y CT_ARCH_mips_o32=y CT_ARCH_ARCH="mips32r2" diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch b/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch deleted file mode 100644 index 393084df324..00000000000 --- a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0001-MIPS-SPARC-fix-wrong-vfork-aliases-in-libpthread.so.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 43c2948756bb6e144c7b871e827bba37d61ad3a3 Mon Sep 17 00:00:00 2001 -From: Aurelien Jarno <aurelien@aurel32.net> -Date: Sat, 18 Jun 2016 19:11:23 +0200 -Subject: [PATCH 1/2] MIPS, SPARC: fix wrong vfork aliases in libpthread.so - -With recent binutils versions the GNU libc fails to build on at least -MISP and SPARC, with this kind of error: - - /home/aurel32/glibc/glibc-build/nptl/libpthread.so:(*IND*+0x0): multiple definition of `vfork@GLIBC_2.0' - /home/aurel32/glibc/glibc-build/nptl/libpthread.so::(.text+0xee50): first defined here - -It appears that on these architectures pt-vfork.S includes vfork.S -(through the alpha version of pt-vfork.S) and that the __vfork aliases -are not conditionalized on IS_IN (libc) like on other architectures. -Therefore the aliases are also wrongly included in libpthread.so. - -Fix this by properly conditionalizing the aliases like on other -architectures. - -Changelog: - * sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Conditionalize - hidden_def, weak_alias and strong_alias on [IS_IN (libc)]. - * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. - * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. ---- - sysdeps/unix/sysv/linux/mips/vfork.S | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S -index 8c6615143708..c0c0ce699159 100644 ---- a/sysdeps/unix/sysv/linux/mips/vfork.S -+++ b/sysdeps/unix/sysv/linux/mips/vfork.S -@@ -106,6 +106,8 @@ L(error): - #endif - END(__vfork) - -+#if IS_IN (libc) - libc_hidden_def(__vfork) - weak_alias (__vfork, vfork) - strong_alias (__vfork, __libc_vfork) -+#endif --- -2.37.3 - diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch b/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch deleted file mode 100644 index e28c7ae99f0..00000000000 --- a/src/ci/docker/host-x86_64/dist-mips-linux/patches/glibc/2.23/0002-MIPS-SPARC-more-fixes-to-the-vfork-aliases-in-libpth.patch +++ /dev/null @@ -1,63 +0,0 @@ -From b87c1ec3fa398646f042a68f0ce0f7d09c1348c7 Mon Sep 17 00:00:00 2001 -From: Aurelien Jarno <aurelien@aurel32.net> -Date: Tue, 21 Jun 2016 23:59:37 +0200 -Subject: [PATCH 2/2] MIPS, SPARC: more fixes to the vfork aliases in - libpthread.so - -Commit 43c29487 tried to fix the vfork aliases in libpthread.so on MIPS -and SPARC, but failed to do it correctly, introducing an ABI change. - -This patch does the remaining changes needed to align the MIPS and SPARC -vfork implementations with the other architectures. That way the the -alpha version of pt-vfork.S works correctly for MIPS and SPARC. The -changes for alpha were done in 82aab97c. - -Changelog: - * sysdeps/unix/sysv/linux/mips/vfork.S (__vfork): Rename into - __libc_vfork. - (__vfork) [IS_IN (libc)]: Remove alias. - (__libc_vfork) [IS_IN (libc)]: Define as an alias. - * sysdeps/unix/sysv/linux/sparc/sparc32/vfork.S: Likewise. - * sysdeps/unix/sysv/linux/sparc/sparc64/vfork.S: Likewise. ---- - sysdeps/unix/sysv/linux/mips/vfork.S | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/sysdeps/unix/sysv/linux/mips/vfork.S b/sysdeps/unix/sysv/linux/mips/vfork.S -index c0c0ce699159..1867c8626ebe 100644 ---- a/sysdeps/unix/sysv/linux/mips/vfork.S -+++ b/sysdeps/unix/sysv/linux/mips/vfork.S -@@ -31,13 +31,13 @@ - LOCALSZ= 1 - FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK - GPOFF= FRAMESZ-(1*SZREG) --NESTED(__vfork,FRAMESZ,sp) -+NESTED(__libc_vfork,FRAMESZ,sp) - #ifdef __PIC__ - SETUP_GP - #endif - PTR_SUBU sp, FRAMESZ - cfi_adjust_cfa_offset (FRAMESZ) -- SETUP_GP64_REG (a5, __vfork) -+ SETUP_GP64_REG (a5, __libc_vfork) - #ifdef __PIC__ - SAVE_GP (GPOFF) - #endif -@@ -104,10 +104,10 @@ L(error): - RESTORE_GP64_REG - j __syscall_error - #endif -- END(__vfork) -+ END(__libc_vfork) - - #if IS_IN (libc) --libc_hidden_def(__vfork) --weak_alias (__vfork, vfork) --strong_alias (__vfork, __libc_vfork) -+weak_alias (__libc_vfork, vfork) -+strong_alias (__libc_vfork, __vfork) -+libc_hidden_def (__vfork) - #endif --- -2.37.3 - diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile index 10f31075e2d..18b0375f400 100644 --- a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile @@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/ COPY host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig index 4b8f7a54920..f295a2fafc6 100644 --- a/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-mips64-linux/mips64-linux-gnu.defconfig @@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4" CT_PREFIX_DIR="/x-tools/${CT_TARGET}" CT_USE_MIRROR=y CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" -CT_PATCH_BUNDLED_LOCAL=y -CT_LOCAL_PATCH_DIR="/tmp/patches" CT_ARCH_MIPS=y CT_ARCH_mips_n64=y CT_ARCH_64=y diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile index 5ab4a53de8a..87407203880 100644 --- a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile @@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/ COPY host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig index 9c8eb5007b7..47d62463565 100644 --- a/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/mips64el-linux-gnu.defconfig @@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4" CT_PREFIX_DIR="/x-tools/${CT_TARGET}" CT_USE_MIRROR=y CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" -CT_PATCH_BUNDLED_LOCAL=y -CT_LOCAL_PATCH_DIR="/tmp/patches" CT_ARCH_MIPS=y CT_ARCH_mips_n64=y CT_ARCH_LE=y diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile index 0bbaf00339d..553f6ea86b7 100644 --- a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile @@ -11,7 +11,6 @@ RUN sh /scripts/rustbuild-setup.sh WORKDIR /tmp COPY scripts/crosstool-ng-build.sh /scripts/ -COPY host-x86_64/dist-mips-linux/patches/ /tmp/patches/ COPY host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig /tmp/crosstool.defconfig RUN /scripts/crosstool-ng-build.sh diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig b/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig index a9dae121e53..5daa83ebc02 100644 --- a/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig +++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/mipsel-linux-gnu.defconfig @@ -2,8 +2,6 @@ CT_CONFIG_VERSION="4" CT_PREFIX_DIR="/x-tools/${CT_TARGET}" CT_USE_MIRROR=y CT_MIRROR_BASE_URL="https://ci-mirrors.rust-lang.org/rustc" -CT_PATCH_BUNDLED_LOCAL=y -CT_LOCAL_PATCH_DIR="/tmp/patches" CT_ARCH_MIPS=y CT_ARCH_mips_o32=y CT_ARCH_LE=y diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 03ec77f507e..6c9071b4191 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -56,9 +56,9 @@ ENV \ CFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ CXX_x86_64_fortanix_unknown_sgx=clang++-11 \ CXXFLAGS_x86_64_fortanix_unknown_sgx="-D__ELF__ -isystem/usr/include/x86_64-linux-gnu -mlvi-hardening -mllvm -x86-experimental-lvi-inline-asm-hardening" \ - AR_i686_unknown_freebsd=i686-unknown-freebsd12-ar \ - CC_i686_unknown_freebsd=i686-unknown-freebsd12-clang \ - CXX_i686_unknown_freebsd=i686-unknown-freebsd12-clang++ \ + AR_i686_unknown_freebsd=i686-unknown-freebsd13-ar \ + CC_i686_unknown_freebsd=i686-unknown-freebsd13-clang \ + CXX_i686_unknown_freebsd=i686-unknown-freebsd13-clang++ \ CC_aarch64_unknown_uefi=clang-11 \ CXX_aarch64_unknown_uefi=clang++-11 \ CC_i686_unknown_uefi=clang-11 \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index f42e6f770eb..fd0f5da8c49 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -29,9 +29,9 @@ COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh ENV \ - AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar \ - CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang \ - CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-clang++ + AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-ar \ + CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang \ + CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd13-clang++ ENV HOSTS=x86_64-unknown-freebsd diff --git a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile index f52e306974c..9ca8cc740a5 100644 --- a/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check-tidy/Dockerfile @@ -1,4 +1,6 @@ -FROM ubuntu:22.04 +# We use the ghcr base image because ghcr doesn't have a rate limit +# and the mingw-check-tidy job doesn't cache docker images in CI. +FROM ghcr.io/rust-lang/ubuntu:22.04 ARG DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y --no-install-recommends \ diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index d1bc0519bc1..d2697ac27ab 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -123,6 +123,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then build_args+=("--build-arg" "SCRIPT_ARG=${DOCKER_SCRIPT}") fi + GHCR_BUILDKIT_IMAGE="ghcr.io/rust-lang/buildkit:buildx-stable-1" # On non-CI jobs, we try to download a pre-built image from the rust-lang-ci # ghcr.io registry. If it is not possible, we fall back to building the image # locally. @@ -140,7 +141,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then elif [[ "$PR_CI_JOB" == "1" ]]; then # Enable a new Docker driver so that --cache-from works with a registry backend - docker buildx create --use --driver docker-container + # Use a custom image to avoid DockerHub rate limits + docker buildx create --use --driver docker-container \ + --driver-opt image=${GHCR_BUILDKIT_IMAGE} # Build the image using registry caching backend retry docker \ @@ -156,7 +159,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then --password-stdin # Enable a new Docker driver so that --cache-from/to works with a registry backend - docker buildx create --use --driver docker-container + # Use a custom image to avoid DockerHub rate limits + docker buildx create --use --driver docker-container \ + --driver-opt image=${GHCR_BUILDKIT_IMAGE} # Build the image using registry caching backend retry docker \ diff --git a/src/ci/docker/scripts/freebsd-toolchain.sh b/src/ci/docker/scripts/freebsd-toolchain.sh index 0d02636db91..b927658b4fd 100755 --- a/src/ci/docker/scripts/freebsd-toolchain.sh +++ b/src/ci/docker/scripts/freebsd-toolchain.sh @@ -5,8 +5,8 @@ set -eux arch=$1 binutils_version=2.40 -freebsd_version=12.3 -triple=$arch-unknown-freebsd12 +freebsd_version=13.4 +triple=$arch-unknown-freebsd13 sysroot=/usr/local/$triple hide_output() { @@ -59,7 +59,7 @@ done # Originally downloaded from: # URL=https://download.freebsd.org/ftp/releases/${freebsd_arch}/${freebsd_version}-RELEASE/base.txz -URL=https://ci-mirrors.rust-lang.org/rustc/2022-05-06-freebsd-${freebsd_version}-${freebsd_arch}-base.txz +URL=https://ci-mirrors.rust-lang.org/rustc/2024-09-13-freebsd-${freebsd_version}-${freebsd_arch}-base.txz curl "$URL" | tar xJf - -C "$sysroot" --wildcards "${files_to_extract[@]}" # Clang can do cross-builds out of the box, if we give it the right diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 1ab70e4e0aa..5e95e3721df 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -35,6 +35,10 @@ runners: os: windows-2022 <<: *base-job + - &job-windows-25 + os: windows-2025 + <<: *base-job + - &job-windows-8c os: windows-2022-8core-32gb <<: *base-job @@ -44,6 +48,8 @@ runners: <<: *base-job - &job-aarch64-linux + # Free some disk space to avoid running out of space during the build. + free_disk: true os: ubuntu-22.04-arm envs: @@ -442,17 +448,30 @@ auto: # Windows Builders # ###################### - - name: x86_64-msvc + - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler - SCRIPT: make ci-msvc - <<: *job-windows-8c + SCRIPT: make ci-msvc-py + <<: *job-windows-25 + + - name: x86_64-msvc-2 + env: + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler + SCRIPT: make ci-msvc-ps1 + <<: *job-windows-25 - - name: i686-msvc + # i686-msvc is split into two jobs to run tests in parallel. + - name: i686-msvc-1 env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc - SCRIPT: make ci-msvc - <<: *job-windows-8c + SCRIPT: make ci-msvc-py + <<: *job-windows + + - name: i686-msvc-2 + env: + RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc + SCRIPT: make ci-msvc-ps1 + <<: *job-windows # x86_64-msvc-ext is split into multiple jobs to run tests in parallel. - name: x86_64-msvc-ext1 diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs index 576bbcea965..8983915d78a 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs @@ -18,8 +18,8 @@ use std::path::Path; use rustc_ast_pretty::pprust::item_to_string; use rustc_data_structures::sync::Lrc; -use rustc_driver::{Compilation, RunCompiler}; -use rustc_interface::interface::Compiler; +use rustc_driver::{Compilation, run_compiler}; +use rustc_interface::interface::{Compiler, Config}; use rustc_middle::ty::TyCtxt; struct MyFileLoader; @@ -51,6 +51,10 @@ fn main() { struct MyCallbacks; impl rustc_driver::Callbacks for MyCallbacks { + fn config(&mut self, config: &mut Config) { + config.file_loader = Some(Box::new(MyFileLoader)); + } + fn after_crate_root_parsing( &mut self, _compiler: &Compiler, @@ -83,10 +87,5 @@ impl rustc_driver::Callbacks for MyCallbacks { } fn main() { - match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) { - mut compiler => { - compiler.set_file_loader(Some(Box::new(MyFileLoader))); - compiler.run(); - } - } + run_compiler(&["main.rs".to_string()], &mut MyCallbacks); } diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs index 90a85d5db21..c894b60444a 100644 --- a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs +++ b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs @@ -18,8 +18,8 @@ use std::path::Path; use rustc_ast_pretty::pprust::item_to_string; use rustc_data_structures::sync::Lrc; -use rustc_driver::{Compilation, RunCompiler}; -use rustc_interface::interface::Compiler; +use rustc_driver::{Compilation, run_compiler}; +use rustc_interface::interface::{Compiler, Config}; use rustc_middle::ty::TyCtxt; struct MyFileLoader; @@ -51,6 +51,10 @@ fn main() { struct MyCallbacks; impl rustc_driver::Callbacks for MyCallbacks { + fn config(&mut self, config: &mut Config) { + config.file_loader = Some(Box::new(MyFileLoader)); + } + fn after_crate_root_parsing( &mut self, _compiler: &Compiler, @@ -90,10 +94,5 @@ impl rustc_driver::Callbacks for MyCallbacks { } fn main() { - match RunCompiler::new(&["main.rs".to_string()], &mut MyCallbacks) { - mut compiler => { - compiler.set_file_loader(Some(Box::new(MyFileLoader))); - compiler.run(); - } - } + run_compiler(&["main.rs".to_string()], &mut MyCallbacks); } diff --git a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md index a6234dc129f..40500e6bc7a 100644 --- a/src/doc/rustc-dev-guide/src/rustc-driver/intro.md +++ b/src/doc/rustc-dev-guide/src/rustc-driver/intro.md @@ -6,7 +6,7 @@ The [`rustc_driver`] is essentially `rustc`'s `main` function. It acts as the glue for running the various phases of the compiler in the correct order, using the interface defined in the [`rustc_interface`] crate. Where possible, using [`rustc_driver`] rather than [`rustc_interface`] is recommended. -The main entry point of [`rustc_driver`] is [`rustc_driver::RunCompiler`][rd_rc]. +The main entry point of [`rustc_driver`] is [`rustc_driver::run_compiler`][rd_rc]. This builder accepts the same command-line args as rustc as well as an implementation of [`Callbacks`][cb] and a couple of other optional options. [`Callbacks`][cb] is a `trait` that allows for custom compiler configuration, as well as allowing custom code to run after different phases of the compilation. @@ -40,7 +40,7 @@ specifically [`rustc_driver_impl::run_compiler`][rdi_rc] [cb]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/trait.Callbacks.html [example]: https://github.com/rust-lang/rustc-dev-guide/blob/master/examples/rustc-interface-example.rs [i_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_interface/interface/fn.run_compiler.html -[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/struct.RunCompiler.html +[rd_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver/fn.run_compiler.html [rdi_rc]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_driver_impl/fn.run_compiler.html [stupid-stats]: https://github.com/nrc/stupid-stats [`nightly-rustc`]: https://doc.rust-lang.org/nightly/nightly-rustc/ diff --git a/src/doc/rustc-dev-guide/src/stability.md b/src/doc/rustc-dev-guide/src/stability.md index 1bfe911c900..230925252ba 100644 --- a/src/doc/rustc-dev-guide/src/stability.md +++ b/src/doc/rustc-dev-guide/src/stability.md @@ -34,7 +34,8 @@ Previously, due to a [rustc bug], stable items inside unstable modules were available to stable code in that location. As of <!-- date-check --> September 2024, items with [accidentally stabilized paths] are marked with the `#[rustc_allowed_through_unstable_modules]` attribute -to prevent code dependent on those paths from breaking. +to prevent code dependent on those paths from breaking. Do *not* add this attribute +to any more items unless that is needed to avoid breaking changes. The `unstable` attribute may also have the `soft` value, which makes it a future-incompatible deny-by-default lint instead of a hard error. This is used diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md index 69f4c864186..426a6ff1da5 100644 --- a/src/doc/rustc-dev-guide/src/tests/directives.md +++ b/src/doc/rustc-dev-guide/src/tests/directives.md @@ -94,7 +94,8 @@ for more details. | Directive | Explanation | Supported test suites | Possible values | |-----------------------------------|--------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|-----------------------------------------------------------------------------------------| | `check-run-results` | Check run test binary `run-{pass,fail}` output snapshot | `ui`, `crashes`, `incremental` if `run-pass` | N/A | -| `error-pattern` | Check that output contains a regex pattern | `ui`, `crashes`, `incremental` if `run-pass` | Regex | +| `error-pattern` | Check that output contains a specific string | `ui`, `crashes`, `incremental` if `run-pass` | String | +| `regex-error-pattern` | Check that output contains a regex pattern | `ui`, `crashes`, `incremental` if `run-pass` | Regex | | `check-stdout` | Check `stdout` against `error-pattern`s from running test binary[^check_stdout] | `ui`, `crashes`, `incremental` | N/A | | `normalize-stderr-32bit` | Normalize actual stderr (for 32-bit platforms) with a rule `"<raw>" -> "<normalized>"` before comparing against snapshot | `ui`, `incremental` | `"<RAW>" -> "<NORMALIZED>"`, `<RAW>`/`<NORMALIZED>` is regex capture and replace syntax | | `normalize-stderr-64bit` | Normalize actual stderr (for 64-bit platforms) with a rule `"<raw>" -> "<normalized>"` before comparing against snapshot | `ui`, `incremental` | `"<RAW>" -> "<NORMALIZED>"`, `<RAW>`/`<NORMALIZED>` is regex capture and replace syntax | @@ -151,6 +152,8 @@ Some examples of `X` in `ignore-X` or `only-X`: `compare-mode-split-dwarf`, `compare-mode-split-dwarf-single` - The two different test modes used by coverage tests: `ignore-coverage-map`, `ignore-coverage-run` +- When testing a dist toolchain: `dist` + - This needs to be enabled with `COMPILETEST_ENABLE_DIST_TESTS=1` The following directives will check rustc build settings and target settings: diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 1c240d1255a..96e3b58f471 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -78,7 +78,7 @@ extern "C" { } #[no_mangle] -pub extern "C" fn main(_argc: isize, _argv: *const *const u8) -> isize { +pub extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { const HELLO: &'static str = "Hello World, the answer is %d\n\0"; unsafe { printf(HELLO.as_ptr() as *const _, 42); diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 32b882e763d..1122bbc5a87 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -46,14 +46,15 @@ allocation. A freestanding program that uses the `Box` sugar for dynamic allocations via `malloc` and `free`: ```rust,ignore (libc-is-finicky) -#![feature(lang_items, start, core_intrinsics, rustc_private, panic_unwind, rustc_attrs)] +#![feature(lang_items, core_intrinsics, rustc_private, panic_unwind, rustc_attrs)] #![allow(internal_features)] #![no_std] +#![no_main] extern crate libc; extern crate unwind; -use core::ffi::c_void; +use core::ffi::{c_int, c_void}; use core::intrinsics; use core::panic::PanicInfo; use core::ptr::NonNull; @@ -91,8 +92,8 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { p } -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: c_int, _argv: *const *const u8) -> c_int { let _x = Box::new(1); 0 diff --git a/src/doc/unstable-book/src/language-features/start.md b/src/doc/unstable-book/src/language-features/start.md deleted file mode 100644 index 09e4875a2e4..00000000000 --- a/src/doc/unstable-book/src/language-features/start.md +++ /dev/null @@ -1,59 +0,0 @@ -# `start` - -The tracking issue for this feature is: [#29633] - -[#29633]: https://github.com/rust-lang/rust/issues/29633 - ------------------------- - -Allows you to mark a function as the entry point of the executable, which is -necessary in `#![no_std]` environments. - -The function marked `#[start]` is passed the command line parameters in the same -format as the C main function (aside from the integer types being used). -It has to be non-generic and have the following signature: - -```rust,ignore (only-for-syntax-highlight) -# let _: -fn(isize, *const *const u8) -> isize -# ; -``` - -This feature should not be confused with the `start` *lang item* which is -defined by the `std` crate and is written `#[lang = "start"]`. - -## Usage together with the `std` crate - -`#[start]` can be used in combination with the `std` crate, in which case the -normal `main` function (which would get called from the `std` crate) won't be -used as an entry point. -The initialization code in `std` will be skipped this way. - -Example: - -```rust -#![feature(start)] - -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - 0 -} -``` - -Unwinding the stack past the `#[start]` function is currently considered -Undefined Behavior (for any unwinding implementation): - -```rust,ignore (UB) -#![feature(start)] - -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - std::panic::catch_unwind(|| { - panic!(); // panic safely gets caught or safely aborts execution - }); - - panic!(); // UB! - - 0 -} -``` diff --git a/src/etc/dec2flt_table.py b/src/etc/dec2flt_table.py index 791186de9c1..ecfdacc1f31 100755 --- a/src/etc/dec2flt_table.py +++ b/src/etc/dec2flt_table.py @@ -43,10 +43,10 @@ def main(): print(HEADER.strip()) print() - print("pub const SMALLEST_POWER_OF_FIVE: i32 = {};".format(min_exp)) - print("pub const LARGEST_POWER_OF_FIVE: i32 = {};".format(max_exp)) - print("pub const N_POWERS_OF_FIVE: usize = ", end="") - print("(LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize;") + print("pub(super) const SMALLEST_POWER_OF_FIVE: i32 = {};".format(min_exp)) + print("pub(super) const LARGEST_POWER_OF_FIVE: i32 = {};".format(max_exp)) + print("pub(super) const N_POWERS_OF_FIVE: usize =") + print(" (LARGEST_POWER_OF_FIVE - SMALLEST_POWER_OF_FIVE + 1) as usize;") print() print_proper_powers(min_exp, max_exp, bias) @@ -97,7 +97,7 @@ def print_proper_powers(min_exp, max_exp, bias): print(STATIC_WARNING.strip()) print("#[rustfmt::skip]") typ = "[(u64, u64); N_POWERS_OF_FIVE]" - print("pub static POWER_OF_FIVE_128: {} = [".format(typ)) + print("pub(super) static POWER_OF_FIVE_128: {} = [".format(typ)) for c, exp in powers: hi = "0x{:x}".format(c // (1 << 64)) lo = "0x{:x}".format(c % (1 << 64)) diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index bfa789b1f39..bdd44b4a993 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -389,6 +389,49 @@ fn write_with_opt_paren<T: fmt::Display>( Ok(()) } +impl Display<'_> { + fn display_sub_cfgs( + &self, + fmt: &mut fmt::Formatter<'_>, + sub_cfgs: &[Cfg], + separator: &str, + ) -> fmt::Result { + let short_longhand = self.1.is_long() && { + let all_crate_features = + sub_cfgs.iter().all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_)))); + let all_target_features = sub_cfgs + .iter() + .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_)))); + + if all_crate_features { + fmt.write_str("crate features ")?; + true + } else if all_target_features { + fmt.write_str("target features ")?; + true + } else { + false + } + }; + + for (i, sub_cfg) in sub_cfgs.iter().enumerate() { + if i != 0 { + fmt.write_str(separator)?; + } + if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { + if self.1.is_html() { + write!(fmt, "<code>{feat}</code>")?; + } else { + write!(fmt, "`{feat}`")?; + } + } else { + write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?; + } + } + Ok(()) + } +} + impl fmt::Display for Display<'_> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match *self.0 { @@ -408,79 +451,9 @@ impl fmt::Display for Display<'_> { Cfg::Any(ref sub_cfgs) => { let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " }; - - let short_longhand = self.1.is_long() && { - let all_crate_features = sub_cfgs - .iter() - .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_)))); - let all_target_features = sub_cfgs - .iter() - .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_)))); - - if all_crate_features { - fmt.write_str("crate features ")?; - true - } else if all_target_features { - fmt.write_str("target features ")?; - true - } else { - false - } - }; - - for (i, sub_cfg) in sub_cfgs.iter().enumerate() { - if i != 0 { - fmt.write_str(separator)?; - } - if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { - if self.1.is_html() { - write!(fmt, "<code>{feat}</code>")?; - } else { - write!(fmt, "`{feat}`")?; - } - } else { - write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?; - } - } - Ok(()) - } - - Cfg::All(ref sub_cfgs) => { - let short_longhand = self.1.is_long() && { - let all_crate_features = sub_cfgs - .iter() - .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_)))); - let all_target_features = sub_cfgs - .iter() - .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_)))); - - if all_crate_features { - fmt.write_str("crate features ")?; - true - } else if all_target_features { - fmt.write_str("target features ")?; - true - } else { - false - } - }; - - for (i, sub_cfg) in sub_cfgs.iter().enumerate() { - if i != 0 { - fmt.write_str(" and ")?; - } - if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { - if self.1.is_html() { - write!(fmt, "<code>{feat}</code>")?; - } else { - write!(fmt, "`{feat}`")?; - } - } else { - write_with_opt_paren(fmt, !sub_cfg.is_simple(), Display(sub_cfg, self.1))?; - } - } - Ok(()) + self.display_sub_cfgs(fmt, sub_cfgs, separator) } + Cfg::All(ref sub_cfgs) => self.display_sub_cfgs(fmt, sub_cfgs, " and "), Cfg::True => fmt.write_str("everywhere"), Cfg::False => fmt.write_str("nowhere"), diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 0dda3466a71..ad67c2ba245 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -1,10 +1,10 @@ -use std::sync::atomic::AtomicBool; -use std::sync::{Arc, LazyLock}; +use std::sync::LazyLock; use std::{io, mem}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::unord::UnordSet; +use rustc_driver::USING_INTERNAL_FEATURES; use rustc_errors::TerminalUrl; use rustc_errors::codes::*; use rustc_errors::emitter::{ @@ -221,7 +221,6 @@ pub(crate) fn create_config( .. }: RustdocOptions, RenderOptions { document_private, .. }: &RenderOptions, - using_internal_features: Arc<AtomicBool>, ) -> rustc_interface::Config { // Add the doc cfg into the doc build. cfgs.push("doc".to_string()); @@ -316,7 +315,7 @@ pub(crate) fn create_config( make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, - using_internal_features, + using_internal_features: &USING_INTERNAL_FEATURES, expanded_args, } } diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 009e9662933..8c3e28ecec3 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -193,7 +193,7 @@ pub(crate) fn run(dcx: DiagCtxtHandle<'_>, input: Input, options: RustdocOptions make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), ice_file: None, - using_internal_features: Arc::default(), + using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES, expanded_args: options.expanded_args.clone(), }; diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 92935c72b47..20a8dc72491 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -150,8 +150,9 @@ pub(crate) fn comma_sep<T: Display>( items: impl Iterator<Item = T>, space_after_comma: bool, ) -> impl Display { - display_fn(move |f| { - for (i, item) in items.enumerate() { + let items = Cell::new(Some(items)); + fmt::from_fn(move |f| { + for (i, item) in items.take().unwrap().enumerate() { if i != 0 { write!(f, ",{}", if space_after_comma { " " } else { "" })?; } @@ -165,7 +166,7 @@ pub(crate) fn print_generic_bounds<'a, 'tcx: 'a>( bounds: &'a [clean::GenericBound], cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let mut bounds_dup = FxHashSet::default(); for (i, bound) in bounds.iter().filter(|b| bounds_dup.insert(*b)).enumerate() { @@ -183,7 +184,7 @@ impl clean::GenericParamDef { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| match &self.kind { + fmt::from_fn(move |f| match &self.kind { clean::GenericParamDefKind::Lifetime { outlives } => { write!(f, "{}", self.name)?; @@ -238,7 +239,7 @@ impl clean::Generics { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let mut real_params = self.params.iter().filter(|p| !p.is_synthetic_param()).peekable(); if real_params.peek().is_none() { return Ok(()); @@ -268,12 +269,12 @@ pub(crate) fn print_where_clause<'a, 'tcx: 'a>( indent: usize, ending: Ending, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let mut where_predicates = gens .where_predicates .iter() .map(|pred| { - display_fn(move |f| { + fmt::from_fn(move |f| { if f.alternate() { f.write_str(" ")?; } else { @@ -376,17 +377,15 @@ impl clean::Lifetime { impl clean::ConstantKind { pub(crate) fn print(&self, tcx: TyCtxt<'_>) -> impl Display + '_ { let expr = self.expr(tcx); - display_fn( - move |f| { - if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) } - }, - ) + fmt::from_fn(move |f| { + if f.alternate() { f.write_str(&expr) } else { write!(f, "{}", Escape(&expr)) } + }) } } impl clean::PolyTrait { fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { print_higher_ranked_params_with_space(&self.generic_params, cx, "for").fmt(f)?; self.trait_.print(cx).fmt(f) }) @@ -398,7 +397,7 @@ impl clean::GenericBound { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| match self { + fmt::from_fn(move |f| match self { clean::GenericBound::Outlives(lt) => write!(f, "{}", lt.print()), clean::GenericBound::TraitBound(ty, modifiers) => { // `const` and `~const` trait bounds are experimental; don't render them. @@ -430,7 +429,7 @@ impl clean::GenericBound { impl clean::GenericArgs { fn print<'a, 'tcx: 'a>(&'a self, cx: &'a Context<'tcx>) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { match self { clean::GenericArgs::AngleBracketed { args, constraints } => { if !args.is_empty() || !constraints.is_empty() { @@ -950,7 +949,7 @@ fn tybounds<'a, 'tcx: 'a>( lt: &'a Option<clean::Lifetime>, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { for (i, bound) in bounds.iter().enumerate() { if i > 0 { write!(f, " + ")?; @@ -971,7 +970,7 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>( cx: &'a Context<'tcx>, keyword: &'static str, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { if !params.is_empty() { f.write_str(keyword)?; f.write_str(if f.alternate() { "<" } else { "<" })?; @@ -982,13 +981,13 @@ fn print_higher_ranked_params_with_space<'a, 'tcx: 'a>( }) } -pub(crate) fn anchor<'a, 'cx: 'a>( +pub(crate) fn anchor<'a: 'cx, 'cx>( did: DefId, text: Symbol, - cx: &'cx Context<'_>, -) -> impl Display + 'a { - let parts = href(did, cx); - display_fn(move |f| { + cx: &'cx Context<'a>, +) -> impl Display + Captures<'a> + 'cx { + fmt::from_fn(move |f| { + let parts = href(did, cx); if let Ok((url, short_ty, fqp)) = parts { write!( f, @@ -1150,7 +1149,7 @@ fn fmt_type( } } clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => { - let lt = display_fn(|f| match l { + let lt = fmt::from_fn(|f| match l { Some(l) => write!(f, "{} ", l.print()), _ => Ok(()), }); @@ -1270,7 +1269,7 @@ impl clean::Type { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'b + Captures<'tcx> { - display_fn(move |f| fmt_type(self, f, false, cx)) + fmt::from_fn(move |f| fmt_type(self, f, false, cx)) } } @@ -1279,7 +1278,7 @@ impl clean::Path { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'b + Captures<'tcx> { - display_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) + fmt::from_fn(move |f| resolved_path(f, self.def_id(), self, false, false, cx)) } } @@ -1289,7 +1288,7 @@ impl clean::Impl { use_absolute: bool, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { f.write_str("impl")?; self.generics.print(cx).fmt(f)?; f.write_str(" ")?; @@ -1407,7 +1406,7 @@ impl clean::Arguments { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { for (i, input) in self.values.iter().enumerate() { write!(f, "{}: ", input.name)?; input.type_.print(cx).fmt(f)?; @@ -1447,7 +1446,7 @@ impl clean::FnDecl { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'b + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let ellipsis = if self.c_variadic { ", ..." } else { "" }; if f.alternate() { write!( @@ -1481,10 +1480,10 @@ impl clean::FnDecl { indent: usize, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { // First, generate the text form of the declaration, with no line wrapping, and count the bytes. let mut counter = WriteCounter(0); - write!(&mut counter, "{:#}", display_fn(|f| { self.inner_full_print(None, f, cx) })) + write!(&mut counter, "{:#}", fmt::from_fn(|f| { self.inner_full_print(None, f, cx) })) .unwrap(); // If the text form was over 80 characters wide, we will line-wrap our output. let line_wrapping_indent = @@ -1566,7 +1565,7 @@ impl clean::FnDecl { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| match &self.output { + fmt::from_fn(move |f| match &self.output { clean::Tuple(tys) if tys.is_empty() => Ok(()), ty if f.alternate() => { write!(f, " -> {:#}", ty.print(cx)) @@ -1618,7 +1617,7 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>( }; let is_doc_hidden = item.is_doc_hidden(); - display_fn(move |f| { + fmt::from_fn(move |f| { if is_doc_hidden { f.write_str("#[doc(hidden)] ")?; } @@ -1692,7 +1691,7 @@ impl clean::Import { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| match self.kind { + fmt::from_fn(move |f| match self.kind { clean::ImportKind::Simple(name) => { if name == self.source.path.last() { write!(f, "use {};", self.source.print(cx)) @@ -1716,7 +1715,7 @@ impl clean::ImportSource { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| match self.did { + fmt::from_fn(move |f| match self.did { Some(did) => resolved_path(f, did, &self.path, true, false, cx), _ => { for seg in &self.path.segments[..self.path.segments.len() - 1] { @@ -1744,7 +1743,7 @@ impl clean::AssocItemConstraint { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { f.write_str(self.assoc.name.as_str())?; self.assoc.args.print(cx).fmt(f)?; match self.kind { @@ -1765,7 +1764,7 @@ impl clean::AssocItemConstraint { } pub(crate) fn print_abi_with_space(abi: ExternAbi) -> impl Display { - display_fn(move |f| { + fmt::from_fn(move |f| { let quot = if f.alternate() { "\"" } else { """ }; match abi { ExternAbi::Rust => Ok(()), @@ -1783,7 +1782,7 @@ impl clean::GenericArg { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| match self { + fmt::from_fn(move |f| match self { clean::GenericArg::Lifetime(lt) => lt.print().fmt(f), clean::GenericArg::Type(ty) => ty.print(cx).fmt(f), clean::GenericArg::Const(ct) => ct.print(cx.tcx()).fmt(f), @@ -1797,24 +1796,9 @@ impl clean::Term { &'a self, cx: &'a Context<'tcx>, ) -> impl Display + 'a + Captures<'tcx> { - display_fn(move |f| match self { + fmt::from_fn(move |f| match self { clean::Term::Type(ty) => ty.print(cx).fmt(f), clean::Term::Constant(ct) => ct.print(cx.tcx()).fmt(f), }) } } - -pub(crate) fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl Display { - struct WithFormatter<F>(Cell<Option<F>>); - - impl<F> Display for WithFormatter<F> - where - F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (self.0.take()).unwrap()(f) - } - } - - WithFormatter(Cell::new(Some(f))) -} diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 62cf2b63f7f..7b2aee4b4a5 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -233,7 +233,7 @@ pub(super) fn write_code( out: &mut impl Write, src: &str, href_context: Option<HrefContext<'_, '_>>, - decoration_info: Option<DecorationInfo>, + decoration_info: Option<&DecorationInfo>, ) { // This replace allows to fix how the code source with DOS backline characters is displayed. let src = src.replace("\r\n", "\n"); @@ -510,12 +510,12 @@ struct Decorations { } impl Decorations { - fn new(info: DecorationInfo) -> Self { + fn new(info: &DecorationInfo) -> Self { // Extract tuples (start, end, kind) into separate sequences of (start, kind) and (end). let (mut starts, mut ends): (Vec<_>, Vec<_>) = info .0 - .into_iter() - .flat_map(|(kind, ranges)| ranges.into_iter().map(move |(lo, hi)| ((lo, kind), hi))) + .iter() + .flat_map(|(&kind, ranges)| ranges.into_iter().map(move |&(lo, hi)| ((lo, kind), hi))) .unzip(); // Sort the sequences in document order. @@ -542,7 +542,7 @@ struct Classifier<'src> { impl<'src> Classifier<'src> { /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code /// file span which will be used later on by the `span_correspondence_map`. - fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> { + fn new(src: &'src str, file_span: Span, decoration_info: Option<&DecorationInfo>) -> Self { let tokens = PeekIter::new(TokenIter { src, cursor: Cursor::new(src) }); let decorations = decoration_info.map(Decorations::new); Classifier { diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index fd5275189d6..fccbb98f80f 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -78,7 +78,7 @@ let a = 4;"; decorations.insert("example2", vec![(22, 32)]); let mut html = Buffer::new(); - write_code(&mut html, src, None, Some(DecorationInfo(decorations))); + write_code(&mut html, src, None, Some(&DecorationInfo(decorations))); expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner()); }); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 9a9ce31caaa..a27a9d202eb 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -69,9 +69,9 @@ use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; use crate::html::format::{ - Buffer, Ending, HrefError, PrintWithSpace, display_fn, href, join_with_double_colon, - print_abi_with_space, print_constness_with_space, print_default_space, print_generic_bounds, - print_where_clause, visibility_print_with_space, + Buffer, Ending, HrefError, PrintWithSpace, href, join_with_double_colon, print_abi_with_space, + print_constness_with_space, print_default_space, print_generic_bounds, print_where_clause, + visibility_print_with_space, }; use crate::html::markdown::{ HeadingOffset, IdMap, Markdown, MarkdownItemInfo, MarkdownSummaryLine, @@ -82,13 +82,14 @@ use crate::scrape_examples::{CallData, CallLocation}; use crate::{DOC_RUST_LANG_ORG_CHANNEL, try_none}; pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ { - crate::html::format::display_fn(move |f| { + fmt::from_fn(move |f| { if !v.ends_with('/') && !v.is_empty() { write!(f, "{v}/") } else { f.write_str(v) } }) } /// Specifies whether rendering directly implemented trait items or ones from a certain Deref /// impl. +#[derive(Copy, Clone)] pub(crate) enum AssocItemRender<'a> { All, DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool }, @@ -309,9 +310,7 @@ impl ItemEntry { impl ItemEntry { pub(crate) fn print(&self) -> impl fmt::Display + '_ { - crate::html::format::display_fn(move |f| { - write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name)) - }) + fmt::from_fn(move |f| write!(f, "<a href=\"{}\">{}</a>", self.url, Escape(&self.name))) } } @@ -513,7 +512,7 @@ fn document<'a, 'cx: 'a>( info!("Documenting {name}"); } - display_fn(move |f| { + fmt::from_fn(move |f| { document_item_info(cx, item, parent).render_into(f).unwrap(); if parent.is_none() { write!(f, "{}", document_full_collapsible(item, cx, heading_offset)) @@ -530,7 +529,7 @@ fn render_markdown<'a, 'cx: 'a>( links: Vec<RenderedLink>, heading_offset: HeadingOffset, ) -> impl fmt::Display + 'a + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { write!( f, "<div class=\"docblock\">{}</div>", @@ -557,7 +556,7 @@ fn document_short<'a, 'cx: 'a>( parent: &'a clean::Item, show_def_docs: bool, ) -> impl fmt::Display + 'a + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { document_item_info(cx, item, Some(parent)).render_into(f).unwrap(); if !show_def_docs { return Ok(()); @@ -605,7 +604,7 @@ fn document_full_inner<'a, 'cx: 'a>( is_collapsible: bool, heading_offset: HeadingOffset, ) -> impl fmt::Display + 'a + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { if let Some(s) = item.opt_doc_value() { debug!("Doc block: =====\n{s}\n====="); if is_collapsible { @@ -1159,7 +1158,7 @@ fn render_attributes_in_pre<'a, 'tcx: 'a>( prefix: &'a str, cx: &'a Context<'tcx>, ) -> impl fmt::Display + Captures<'a> + Captures<'tcx> { - crate::html::format::display_fn(move |f| { + fmt::from_fn(move |f| { for a in it.attributes(cx.tcx(), cx.cache(), false) { writeln!(f, "{prefix}{a}")?; } @@ -1256,9 +1255,9 @@ fn render_assoc_items<'a, 'cx: 'a>( it: DefId, what: AssocItemRender<'a>, ) -> impl fmt::Display + 'a + Captures<'cx> { - let mut derefs = DefIdSet::default(); - derefs.insert(it); - display_fn(move |f| { + fmt::from_fn(move |f| { + let mut derefs = DefIdSet::default(); + derefs.insert(it); render_assoc_items_inner(f, cx, containing_item, it, what, &mut derefs); Ok(()) }) @@ -2577,7 +2576,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &Context<'_>, item: &clean file_span, cx, &cx.root_path(), - highlight::DecorationInfo(decoration_info), + &highlight::DecorationInfo(decoration_info), sources::SourceContext::Embedded(sources::ScrapedInfo { needs_expansion, offset: line_min, diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 1376bdb2e90..37fea09ace3 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -30,7 +30,7 @@ use crate::formats::Impl; use crate::formats::item_type::ItemType; use crate::html::escape::{Escape, EscapeBodyTextWithWbr}; use crate::html::format::{ - Buffer, Ending, PrintWithSpace, display_fn, join_with_double_colon, print_abi_with_space, + Buffer, Ending, PrintWithSpace, join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause, visibility_print_with_space, }; use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine}; @@ -92,7 +92,7 @@ macro_rules! item_template_methods { () => {}; (document $($rest:tt)*) => { fn document<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let (item, cx) = self.item_and_cx(); let v = document(cx, item, None, HeadingOffset::H2); write!(f, "{v}") @@ -102,7 +102,7 @@ macro_rules! item_template_methods { }; (document_type_layout $($rest:tt)*) => { fn document_type_layout<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let (item, cx) = self.item_and_cx(); let def_id = item.item_id.expect_def_id(); let v = document_type_layout(cx, def_id); @@ -113,7 +113,7 @@ macro_rules! item_template_methods { }; (render_attributes_in_pre $($rest:tt)*) => { fn render_attributes_in_pre<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let (item, cx) = self.item_and_cx(); let v = render_attributes_in_pre(item, "", cx); write!(f, "{v}") @@ -123,7 +123,7 @@ macro_rules! item_template_methods { }; (render_assoc_items $($rest:tt)*) => { fn render_assoc_items<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let (item, cx) = self.item_and_cx(); let def_id = item.item_id.expect_def_id(); let v = render_assoc_items(cx, item, def_id, AssocItemRender::All); @@ -140,10 +140,9 @@ macro_rules! item_template_methods { }; } -const ITEM_TABLE_OPEN: &str = "<ul class=\"item-table\">"; -const ITEM_TABLE_CLOSE: &str = "</ul>"; -const ITEM_TABLE_ROW_OPEN: &str = "<li>"; -const ITEM_TABLE_ROW_CLOSE: &str = "</li>"; +const ITEM_TABLE_OPEN: &str = "<dl class=\"item-table\">"; +const REEXPORTS_TABLE_OPEN: &str = "<dl class=\"item-table reexports\">"; +const ITEM_TABLE_CLOSE: &str = "</dl>"; // A component in a `use` path, like `string` in std::string::ToString struct PathComponent { @@ -400,37 +399,32 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl w.write_str(ITEM_TABLE_CLOSE); } last_section = Some(my_section); - write_section_heading( - w, - my_section.name(), - &cx.derive_id(my_section.id()), - None, - ITEM_TABLE_OPEN, - ); + let section_id = my_section.id(); + let tag = + if section_id == "reexports" { REEXPORTS_TABLE_OPEN } else { ITEM_TABLE_OPEN }; + write_section_heading(w, my_section.name(), &cx.derive_id(section_id), None, tag); } match myitem.kind { clean::ExternCrateItem { ref src } => { use crate::html::format::anchor; - w.write_str(ITEM_TABLE_ROW_OPEN); match *src { Some(src) => write!( w, - "<div class=\"item-name\"><code>{}extern crate {} as {};", + "<dt><code>{}extern crate {} as {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), src, cx), EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), ), None => write!( w, - "<div class=\"item-name\"><code>{}extern crate {};", + "<dt><code>{}extern crate {};", visibility_print_with_space(myitem, cx), anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx), ), } - w.write_str("</code></div>"); - w.write_str(ITEM_TABLE_ROW_CLOSE); + w.write_str("</code></dt>"); } clean::ImportItem(ref import) => { @@ -438,28 +432,20 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl extra_info_tags(tcx, myitem, item, Some(import_def_id)).to_string() }); - w.write_str(ITEM_TABLE_ROW_OPEN); let id = match import.kind { clean::ImportKind::Simple(s) => { format!(" id=\"{}\"", cx.derive_id(format!("reexport.{s}"))) } clean::ImportKind::Glob => String::new(), }; - let (stab_tags_before, stab_tags_after) = if stab_tags.is_empty() { - ("", "") - } else { - ("<div class=\"desc docblock-short\">", "</div>") - }; write!( w, - "<div class=\"item-name\"{id}>\ - <code>{vis}{imp}</code>\ - </div>\ - {stab_tags_before}{stab_tags}{stab_tags_after}", + "<dt{id}>\ + <code>{vis}{imp}</code>{stab_tags}\ + </dt>", vis = visibility_print_with_space(myitem, cx), imp = import.print(cx), ); - w.write_str(ITEM_TABLE_ROW_CLOSE); } _ => { @@ -492,22 +478,18 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl _ => "", }; - w.write_str(ITEM_TABLE_ROW_OPEN); let docs = MarkdownSummaryLine(&myitem.doc_value(), &myitem.links(cx)).into_string(); - let (docs_before, docs_after) = if docs.is_empty() { - ("", "") - } else { - ("<div class=\"desc docblock-short\">", "</div>") - }; + let (docs_before, docs_after) = + if docs.is_empty() { ("", "") } else { ("<dd>", "</dd>") }; write!( w, - "<div class=\"item-name\">\ + "<dt>\ <a class=\"{class}\" href=\"{href}\" title=\"{title}\">{name}</a>\ {visibility_and_hidden}\ {unsafety_flag}\ {stab_tags}\ - </div>\ + </dt>\ {docs_before}{docs}{docs_after}", name = EscapeBodyTextWithWbr(myitem.name.unwrap().as_str()), visibility_and_hidden = visibility_and_hidden, @@ -521,7 +503,6 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl .collect::<Vec<_>>() .join(" "), ); - w.write_str(ITEM_TABLE_ROW_CLOSE); } } } @@ -539,13 +520,13 @@ fn extra_info_tags<'a, 'tcx: 'a>( parent: &'a clean::Item, import_def_id: Option<DefId>, ) -> impl fmt::Display + 'a + Captures<'tcx> { - display_fn(move |f| { + fmt::from_fn(move |f| { fn tag_html<'a>( class: &'a str, title: &'a str, contents: &'a str, ) -> impl fmt::Display + 'a { - display_fn(move |f| { + fmt::from_fn(move |f| { write!( f, r#"<wbr><span class="stab {class}" title="{title}">{contents}</span>"#, @@ -933,7 +914,6 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra let mut extern_crates = FxIndexSet::default(); if !t.is_dyn_compatible(cx.tcx()) { - // FIXME(dyn_compat_renaming): Update the URL once the Reference is updated. write_section_heading( w, "Dyn Compatibility", @@ -941,7 +921,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra None, format!( "<div class=\"dyn-compatibility-info\"><p>This trait is <b>not</b> \ - <a href=\"{base}/reference/items/traits.html#object-safety\">dyn compatible</a>.</p>\ + <a href=\"{base}/reference/items/traits.html#dyn-compatibility\">dyn compatible</a>.</p>\ <p><i>In older versions of Rust, dyn compatibility was called \"object safety\", \ so this trait is not object safe.</i></p></div>", base = crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL @@ -1395,7 +1375,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni impl<'a, 'cx: 'a> ItemUnion<'a, 'cx> { fn render_union<'b>(&'b self) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let v = render_union(self.it, Some(&self.s.generics), &self.s.fields, self.cx); write!(f, "{v}") }) @@ -1405,7 +1385,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni &'b self, field: &'a clean::Item, ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let v = document(self.cx, field, Some(self.it), HeadingOffset::H3); write!(f, "{v}") }) @@ -1419,7 +1399,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni &'b self, ty: &'a clean::Type, ) -> impl fmt::Display + Captures<'a> + 'b + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { let v = ty.print(self.cx); write!(f, "{v}") }) @@ -1446,7 +1426,7 @@ fn print_tuple_struct_fields<'a, 'cx: 'a>( cx: &'a Context<'cx>, s: &'a [clean::Item], ) -> impl fmt::Display + 'a + Captures<'cx> { - display_fn(|f| { + fmt::from_fn(|f| { if !s.is_empty() && s.iter().all(|field| { matches!(field.kind, clean::StrippedItem(box clean::StructFieldItem(..))) @@ -2171,7 +2151,7 @@ fn render_union<'a, 'cx: 'a>( fields: &'a [clean::Item], cx: &'a Context<'cx>, ) -> impl fmt::Display + 'a + Captures<'cx> { - display_fn(move |mut f| { + fmt::from_fn(move |mut f| { write!(f, "{}union {}", visibility_print_with_space(it, cx), it.name.unwrap(),)?; let where_displayed = g @@ -2351,7 +2331,7 @@ fn document_non_exhaustive_header(item: &clean::Item) -> &str { } fn document_non_exhaustive(item: &clean::Item) -> impl fmt::Display + '_ { - display_fn(|f| { + fmt::from_fn(|f| { if item.is_non_exhaustive() { write!( f, diff --git a/src/librustdoc/html/render/sidebar.rs b/src/librustdoc/html/render/sidebar.rs index 881df8b0050..23ac568fdf8 100644 --- a/src/librustdoc/html/render/sidebar.rs +++ b/src/librustdoc/html/render/sidebar.rs @@ -100,18 +100,17 @@ impl<'a> Link<'a> { } pub(crate) mod filters { - use std::fmt::Display; + use std::fmt::{self, Display}; use rinja::filters::Safe; use crate::html::escape::EscapeBodyTextWithWbr; - use crate::html::render::display_fn; pub(crate) fn wrapped<T>(v: T) -> rinja::Result<Safe<impl Display>> where T: Display, { let string = v.to_string(); - Ok(Safe(display_fn(move |f| EscapeBodyTextWithWbr(&string).fmt(f)))) + Ok(Safe(fmt::from_fn(move |f| EscapeBodyTextWithWbr(&string).fmt(f)))) } } diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs index 9317844956d..0f01db5f6bc 100644 --- a/src/librustdoc/html/render/type_layout.rs +++ b/src/librustdoc/html/render/type_layout.rs @@ -9,7 +9,6 @@ use rustc_middle::ty::layout::LayoutError; use rustc_middle::ty::{self}; use rustc_span::symbol::Symbol; -use crate::html::format::display_fn; use crate::html::render::Context; #[derive(Template)] @@ -31,7 +30,7 @@ pub(crate) fn document_type_layout<'a, 'cx: 'a>( cx: &'a Context<'cx>, ty_def_id: DefId, ) -> impl fmt::Display + 'a + Captures<'cx> { - display_fn(move |f| { + fmt::from_fn(move |f| { if !cx.shared.show_type_layout { return Ok(()); } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 9827f97d28d..1ac0c10c612 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -17,7 +17,7 @@ use crate::clean::utils::has_doc_flag; use crate::docfs::PathError; use crate::error::Error; use crate::html::render::Context; -use crate::html::{format, highlight, layout}; +use crate::html::{highlight, layout}; use crate::visit::DocVisitor; pub(crate) fn render(cx: &mut Context<'_>, krate: &clean::Crate) -> Result<(), Error> { @@ -249,7 +249,7 @@ impl SourceCollector<'_, '_> { file_span, self.cx, &root_path, - highlight::DecorationInfo::default(), + &highlight::DecorationInfo::default(), SourceContext::Standalone { file_path }, ) }, @@ -328,13 +328,13 @@ pub(crate) fn print_src( file_span: rustc_span::Span, context: &Context<'_>, root_path: &str, - decoration_info: highlight::DecorationInfo, + decoration_info: &highlight::DecorationInfo, source_context: SourceContext<'_>, ) { - let current_href = context - .href_from_span(clean::Span::new(file_span), false) - .expect("only local crates should have sources emitted"); - let code = format::display_fn(move |fmt| { + let code = fmt::from_fn(move |fmt| { + let current_href = context + .href_from_span(clean::Span::new(file_span), false) + .expect("only local crates should have sources emitted"); highlight::write_code( fmt, s, diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index a1ab258ff30..b994a43868c 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -242,7 +242,7 @@ h1, h2, h3, h4, h5, h6, .mobile-topbar, .search-input, .search-results .result-name, -.item-name > a, +.item-table dt > a, .out-of-band, .sub-heading, span.since, @@ -385,11 +385,11 @@ details:not(.toggle) summary { code, pre, .code-header, .type-signature { font-family: "Source Code Pro", monospace; } -.docblock code, .docblock-short code { +.docblock code, .item-table dd code { border-radius: 3px; padding: 0 0.125em; } -.docblock pre code, .docblock-short pre code { +.docblock pre code, .item-table dd pre code { padding: 0; } pre { @@ -887,13 +887,13 @@ both the code example and the line numbers, so we need to remove the radius in t text-align: center; } -.docblock-short { +.item-table dd { overflow-wrap: break-word; overflow-wrap: anywhere; } /* Wrap non-pre code blocks (`text`) but not (```text```). */ .docblock :not(pre) > code, -.docblock-short code { +.item-table dd code { white-space: pre-wrap; } @@ -938,7 +938,7 @@ rustdoc-toolbar { min-height: 60px; } -.docblock code, .docblock-short code, +.docblock code, .item-table dd code, pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { background-color: var(--code-block-background-color); border-radius: var(--code-block-border-radius); @@ -964,7 +964,7 @@ pre, .rustdoc.src .example-wrap, .example-wrap .src-line-numbers { background: var(--table-alt-row-background-color); } -.docblock .stab, .docblock-short .stab, .docblock p code { +.docblock .stab, .item-table dd .stab, .docblock p code { display: inline-block; } @@ -1069,7 +1069,7 @@ because of the `[-]` element which would overlap with it. */ .example-wrap .rust a:hover, .all-items a:hover, .docblock a:not(.scrape-help):not(.tooltip):hover:not(.doc-anchor), -.docblock-short a:not(.scrape-help):not(.tooltip):hover, +.item-table dd a:not(.scrape-help):not(.tooltip):hover, .item-info a { text-decoration: underline; } @@ -1102,20 +1102,17 @@ table, } .item-table { - display: table; padding: 0; margin: 0; width: 100%; } -.item-table > li { - display: table-row; -} -.item-table > li > div { - display: table-cell; -} -.item-table > li > .item-name { +.item-table > dt { padding-right: 1.25rem; } +.item-table > dd { + margin-inline-start: 0; + margin-left: 0; +} .search-results-title { margin-top: 0; @@ -1415,7 +1412,7 @@ so that we can apply CSS-filters to change the arrow color in themes */ padding: 3px; margin-bottom: 5px; } -.item-name .stab { +.item-table dt .stab { margin-left: 0.3125em; } .stab { @@ -2476,7 +2473,6 @@ in src-script.js and main.js } /* Display an alternating layout on tablets and phones */ - .item-table, .item-row, .item-table > li, .item-table > li > div, .search-results > a, .search-results > a > div { display: block; } @@ -2485,7 +2481,7 @@ in src-script.js and main.js .search-results > a { padding: 5px 0px; } - .search-results > a > div.desc, .item-table > li > div.desc { + .search-results > a > div.desc, .item-table dd { padding-left: 2em; } .search-results .result-name { @@ -2546,12 +2542,20 @@ in src-script.js and main.js box-shadow: 0 0 4px var(--main-background-color); } - .item-table > li > .item-name { - width: 33%; + /* Since the screen is wide enough, we show items on their description on the same line. */ + .item-table:not(.reexports) { + display: grid; + grid-template-columns: 33% 67%; } - .item-table > li > div { + .item-table > dt, .item-table > dd { overflow-wrap: anywhere; } + .item-table > dt { + grid-column-start: 1; + } + .item-table > dd { + grid-column-start: 2; + } } @media print { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index ba620b6cb6b..bb954a31891 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -5,6 +5,7 @@ #![feature(rustc_private)] #![feature(assert_matches)] #![feature(box_patterns)] +#![feature(debug_closure_helpers)] #![feature(file_buffered)] #![feature(if_let_guard)] #![feature(impl_trait_in_assoc_type)] @@ -73,8 +74,6 @@ extern crate tikv_jemalloc_sys as jemalloc_sys; use std::env::{self, VarError}; use std::io::{self, IsTerminal}; use std::process; -use std::sync::Arc; -use std::sync::atomic::AtomicBool; use rustc_errors::DiagCtxtHandle; use rustc_interface::interface; @@ -158,7 +157,7 @@ pub fn main() { let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default()); - let using_internal_features = rustc_driver::install_ice_hook( + rustc_driver::install_ice_hook( "https://github.com/rust-lang/rust/issues/new\ ?labels=C-bug%2C+I-ICE%2C+T-rustdoc&template=ice.md", |_| (), @@ -179,7 +178,7 @@ pub fn main() { let exit_code = rustc_driver::catch_with_exit_code(|| { let at_args = rustc_driver::args::raw_args(&early_dcx)?; - main_args(&mut early_dcx, &at_args, using_internal_features); + main_args(&mut early_dcx, &at_args); Ok(()) }); process::exit(exit_code); @@ -768,11 +767,7 @@ fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> { Ok(()) } -fn main_args( - early_dcx: &mut EarlyDiagCtxt, - at_args: &[String], - using_internal_features: Arc<AtomicBool>, -) { +fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { // Throw away the first argument, the name of the binary. // In case of at_args being empty, as might be the case by // passing empty argument array to execve under some platforms, @@ -825,8 +820,7 @@ fn main_args( (false, Some(md_input)) => { let md_input = md_input.to_owned(); let edition = options.edition; - let config = - core::create_config(input, options, &render_options, using_internal_features); + let config = core::create_config(input, options, &render_options); // `markdown::render` can invoke `doctest::make_test`, which // requires session globals and a thread pool, so we use @@ -859,7 +853,7 @@ fn main_args( let scrape_examples_options = options.scrape_examples_options.clone(); let bin_crate = options.bin_crate; - let config = core::create_config(input, options, &render_options, using_internal_features); + let config = core::create_config(input, options, &render_options); let registered_lints = config.register_lints.is_some(); diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index 5a99977ded5..916f0ab3cc8 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -1099,8 +1099,7 @@ pub struct Trait { pub is_auto: bool, /// Whether the trait is marked as `unsafe`. pub is_unsafe: bool, - // FIXME(dyn_compat_renaming): Update the URL once the Reference is updated and hits stable. - /// Whether the trait is [dyn compatible](https://doc.rust-lang.org/reference/items/traits.html#object-safety)[^1]. + /// Whether the trait is [dyn compatible](https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility)[^1]. /// /// [^1]: Formerly known as "object safe". pub is_dyn_compatible: bool, diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 5418acc105e..26bea8d633a 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -18,6 +18,7 @@ use rustc_session::declare_lint_pass; use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; +use rustc_trait_selection::traits::supertrait_def_ids; declare_clippy_lint! { /// ### What it does @@ -270,7 +271,7 @@ fn check_trait_items(cx: &LateContext<'_>, visited_trait: &Item<'_>, trait_items // fill the set with current and super traits fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) { if set.insert(traitt) { - for supertrait in cx.tcx.supertrait_def_ids(traitt) { + for supertrait in supertrait_def_ids(cx.tcx, traitt) { fill_trait_set(supertrait, set, cx); } } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 428b40c5771..104ae154e36 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -109,7 +109,7 @@ fn check_rvalue<'tcx>( ) -> McfResult { match rvalue { Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), - Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => { + Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => { check_place(tcx, *place, span, body, msrv) }, Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv), diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index 75ef60a5dc8..68edefd3095 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -186,7 +186,7 @@ pub fn main() { rustc_driver::init_rustc_env_logger(&early_dcx); - let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| { + rustc_driver::install_ice_hook(BUG_REPORT_URL, |dcx| { // FIXME: this macro calls unwrap internally but is called in a panicking context! It's not // as simple as moving the call from the hook to main, because `install_ice_hook` doesn't // accept a generic closure. @@ -236,7 +236,7 @@ pub fn main() { let mut args: Vec<String> = orig_args.clone(); pass_sysroot_env_if_given(&mut args, sys_root_env); - rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run(); + rustc_driver::run_compiler(&args, &mut DefaultCallbacks); return Ok(()); } @@ -295,13 +295,9 @@ pub fn main() { let clippy_enabled = !cap_lints_allow && relevant_package && !info_query; if clippy_enabled { args.extend(clippy_args); - rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }) - .set_using_internal_features(using_internal_features) - .run(); + rustc_driver::run_compiler(&args, &mut ClippyCallbacks { clippy_args_var }); } else { - rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }) - .set_using_internal_features(using_internal_features) - .run(); + rustc_driver::run_compiler(&args, &mut RustcCallbacks { clippy_args_var }); } Ok(()) })) diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed index f66554de300..26c6a5033d1 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed @@ -1,10 +1,9 @@ #![warn(clippy::borrow_as_ptr)] -#![feature(lang_items, start, libc)] #![no_std] +#![crate_type = "lib"] #[clippy::msrv = "1.75"] -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let val = 1; let _p = core::ptr::addr_of!(val); @@ -12,11 +11,3 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { let _p_mut = core::ptr::addr_of_mut!(val_mut); 0 } - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs index 1fc254aafa7..d8d8b4c380c 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs @@ -1,10 +1,9 @@ #![warn(clippy::borrow_as_ptr)] -#![feature(lang_items, start, libc)] #![no_std] +#![crate_type = "lib"] #[clippy::msrv = "1.75"] -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let val = 1; let _p = &val as *const i32; @@ -12,11 +11,3 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { let _p_mut = &mut val_mut as *mut i32; 0 } - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr index 6802c86ec95..488e0bd9677 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.stderr @@ -1,5 +1,5 @@ error: borrow as raw pointer - --> tests/ui/borrow_as_ptr_no_std.rs:9:14 + --> tests/ui/borrow_as_ptr_no_std.rs:8:14 | LL | let _p = &val as *const i32; | ^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of!(val)` @@ -8,7 +8,7 @@ LL | let _p = &val as *const i32; = help: to override `-D warnings` add `#[allow(clippy::borrow_as_ptr)]` error: borrow as raw pointer - --> tests/ui/borrow_as_ptr_no_std.rs:12:18 + --> tests/ui/borrow_as_ptr_no_std.rs:11:18 | LL | let _p_mut = &mut val_mut as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `core::ptr::addr_of_mut!(val_mut)` diff --git a/src/tools/clippy/tests/ui/box_default_no_std.rs b/src/tools/clippy/tests/ui/box_default_no_std.rs index 4326abc9a54..edb701fcd08 100644 --- a/src/tools/clippy/tests/ui/box_default_no_std.rs +++ b/src/tools/clippy/tests/ui/box_default_no_std.rs @@ -1,6 +1,6 @@ -#![feature(lang_items, start, libc)] #![warn(clippy::box_default)] #![no_std] +#![crate_type = "lib"] pub struct NotBox<T> { _value: T, @@ -18,16 +18,7 @@ impl<T: Default> Default for NotBox<T> { } } -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let _p = NotBox::new(isize::default()); 0 } - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-7410.rs b/src/tools/clippy/tests/ui/crashes/ice-7410.rs index ccf6d7ff94f..addbca54e80 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7410.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7410.rs @@ -1,7 +1,7 @@ //@compile-flags: -Clink-arg=-nostartfiles //@ignore-target: apple windows -#![feature(lang_items, start, libc)] +#![crate_type = "lib"] #![no_std] #![allow(clippy::if_same_then_else)] #![allow(clippy::redundant_pattern_matching)] @@ -15,18 +15,9 @@ impl Drop for S { fn drop(&mut self) {} } -#[start] -fn main(argc: isize, argv: *const *const u8) -> isize { +pub fn main(argc: isize, argv: *const *const u8) -> isize { if let Some(_) = Some(S) { } else { } 0 } - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs deleted file mode 100644 index 9e5b2a48903..00000000000 --- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@compile-flags: -Clink-arg=-nostartfiles -//@ignore-target: apple - -#![feature(lang_items, start, libc)] -#![no_std] - -use core::panic::PanicInfo; -use core::sync::atomic::{AtomicUsize, Ordering}; - -static N: AtomicUsize = AtomicUsize::new(0); - -#[warn(clippy::main_recursion)] -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { - let x = N.load(Ordering::Relaxed); - N.store(x + 1, Ordering::Relaxed); - - if x < 3 { - main(_argc, _argv); - } - - 0 -} - -#[allow(clippy::empty_loop)] -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed index 32bccd3a0ff..e09a913ef06 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed +++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed @@ -1,11 +1,10 @@ #![no_std] -#![feature(lang_items, start, libc)] #![crate_type = "lib"] use core::panic::PanicInfo; #[warn(clippy::all)] -fn main() { +pub fn main() { let mut a = 42; let mut b = 1337; diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs index 8ed45a33465..536e71b4a25 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs +++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs @@ -1,11 +1,10 @@ #![no_std] -#![feature(lang_items, start, libc)] #![crate_type = "lib"] use core::panic::PanicInfo; #[warn(clippy::all)] -fn main() { +pub fn main() { let mut a = 42; let mut b = 1337; diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr index bcc8684f7c2..3e37bd95ef3 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr +++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr @@ -1,5 +1,5 @@ error: this looks like you are trying to swap `a` and `b` - --> tests/ui/crate_level_checks/no_std_swap.rs:12:5 + --> tests/ui/crate_level_checks/no_std_swap.rs:11:5 | LL | / a = b; ... | diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs index c9650312db8..03f5ca31f5f 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.rs +++ b/src/tools/clippy/tests/ui/def_id_nocore.rs @@ -1,6 +1,6 @@ //@ignore-target: apple -#![feature(no_core, lang_items, start)] +#![feature(no_core, lang_items)] #![no_core] #![allow(clippy::missing_safety_doc)] diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs index 1bb895bda75..9bfcbfba969 100644 --- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs @@ -2,27 +2,11 @@ //@ignore-target: apple #![warn(clippy::empty_loop)] -#![feature(lang_items, start, libc)] +#![crate_type = "lib"] #![no_std] -use core::panic::PanicInfo; - -#[start] -fn main(argc: isize, argv: *const *const u8) -> isize { +pub fn main(argc: isize, argv: *const *const u8) -> isize { // This should trigger the lint loop {} //~^ ERROR: empty `loop {}` wastes CPU cycles } - -#[panic_handler] -fn panic(_info: &PanicInfo) -> ! { - // This should NOT trigger the lint - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() { - // This should also trigger the lint - loop {} - //~^ ERROR: empty `loop {}` wastes CPU cycles -} diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr index f4a18204c3c..f36fb9d9e3f 100644 --- a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr @@ -1,5 +1,5 @@ error: empty `loop {}` wastes CPU cycles - --> tests/ui/empty_loop_no_std.rs:13:5 + --> tests/ui/empty_loop_no_std.rs:10:5 | LL | loop {} | ^^^^^^^ @@ -8,13 +8,5 @@ LL | loop {} = note: `-D clippy::empty-loop` implied by `-D warnings` = help: to override `-D warnings` add `#[allow(clippy::empty_loop)]` -error: empty `loop {}` wastes CPU cycles - --> tests/ui/empty_loop_no_std.rs:26:5 - | -LL | loop {} - | ^^^^^^^ - | - = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs index 8ea75fae89b..81e4e0380da 100644 --- a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs +++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs @@ -1,4 +1,4 @@ -#![feature(lang_items, start)] +#![crate_type = "lib"] #![warn(clippy::imprecise_flops)] #![warn(clippy::suboptimal_flops)] #![no_std] @@ -17,15 +17,6 @@ fn fake_abs1(num: f64) -> f64 { if num >= 0.0 { num } else { -num } } -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +pub fn main(_argc: isize, _argv: *const *const u8) -> isize { 0 } - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs index d2f9e34a5ce..fdde68790a8 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -6,7 +6,6 @@ //@aux-build:../auxiliary/proc_macros.rs #![warn(clippy::missing_const_for_fn)] -#![feature(start)] #![feature(type_alias_impl_trait)] extern crate helper; @@ -71,15 +70,6 @@ mod with_test_fn { } } -// Allowing on this function, because it would lint, which we don't want in this case. -// if we have `#[start]` and `#[test]` check `is_entrypoint_fn(cx, def_id.to_def_id())` is stopped -// working -#[allow(clippy::missing_const_for_fn)] -#[start] -fn init(num: isize, something: *const *const u8) -> isize { - 1 -} - trait Foo { // This should not be suggested to be made const // (rustc doesn't allow const trait methods) diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed index 497e0e24317..771ab1ab21a 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed +++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed @@ -1,22 +1,13 @@ #![warn(clippy::missing_spin_loop)] -#![feature(lang_items, start, libc)] +#![crate_type = "lib"] #![no_std] use core::sync::atomic::{AtomicBool, Ordering}; -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +pub fn main(_argc: isize, _argv: *const *const u8) -> isize { // This should trigger the lint let b = AtomicBool::new(true); // This should lint with `core::hint::spin_loop()` while b.load(Ordering::Acquire) { core::hint::spin_loop() } 0 } - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs index 1c85a9c58d6..bf890fc4066 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs +++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs @@ -1,22 +1,13 @@ #![warn(clippy::missing_spin_loop)] -#![feature(lang_items, start, libc)] +#![crate_type = "lib"] #![no_std] use core::sync::atomic::{AtomicBool, Ordering}; -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +pub fn main(_argc: isize, _argv: *const *const u8) -> isize { // This should trigger the lint let b = AtomicBool::new(true); // This should lint with `core::hint::spin_loop()` while b.load(Ordering::Acquire) {} 0 } - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr index 7911620d32c..d4b9485be46 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr +++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.stderr @@ -1,5 +1,5 @@ error: busy-waiting loop should at least have a spin loop hint - --> tests/ui/missing_spin_loop_no_std.rs:12:37 + --> tests/ui/missing_spin_loop_no_std.rs:11:37 | LL | while b.load(Ordering::Acquire) {} | ^^ help: try: `{ core::hint::spin_loop() }` diff --git a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs index 1e7a028a7fc..c9f4996c368 100644 --- a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs +++ b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs @@ -1,5 +1,6 @@ -#![feature(lang_items, start, libc)] +#![feature(lang_items, libc)] #![no_std] +#![no_main] #![warn(clippy::result_unit_err)] #[clippy::msrv = "1.80"] @@ -12,8 +13,8 @@ pub fn returns_unit_error_lint() -> Result<u32, ()> { Err(()) } -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { 0 } diff --git a/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr b/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr index 33692e60554..a7807f089ab 100644 --- a/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr +++ b/src/tools/clippy/tests/ui/result_unit_error_no_std.stderr @@ -1,5 +1,5 @@ error: this returns a `Result<_, ()>` - --> tests/ui/result_unit_error_no_std.rs:11:1 + --> tests/ui/result_unit_error_no_std.rs:12:1 | LL | pub fn returns_unit_error_lint() -> Result<u32, ()> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed index 4f4d19e883d..25143eee8cc 100644 --- a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed +++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed @@ -1,19 +1,10 @@ -#![feature(lang_items, start, libc)] +#![crate_type = "lib"] #![no_std] #![deny(clippy::zero_ptr)] -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let _ = core::ptr::null::<usize>(); let _ = core::ptr::null_mut::<f64>(); let _: *const u8 = core::ptr::null(); 0 } - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs index 54954d8d13f..965733b45d9 100644 --- a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs +++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs @@ -1,19 +1,10 @@ -#![feature(lang_items, start, libc)] +#![crate_type = "lib"] #![no_std] #![deny(clippy::zero_ptr)] -#[start] -fn main(_argc: isize, _argv: *const *const u8) -> isize { +pub fn main(_argc: isize, _argv: *const *const u8) -> isize { let _ = 0 as *const usize; let _ = 0 as *mut f64; let _: *const u8 = 0 as *const _; 0 } - -#[panic_handler] -fn panic(_info: &core::panic::PanicInfo) -> ! { - loop {} -} - -#[lang = "eh_personality"] -extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr index 42a1a41ca94..014bf312bf3 100644 --- a/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr +++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.stderr @@ -1,5 +1,5 @@ error: `0 as *const _` detected - --> tests/ui/zero_ptr_no_std.rs:7:13 + --> tests/ui/zero_ptr_no_std.rs:6:13 | LL | let _ = 0 as *const usize; | ^^^^^^^^^^^^^^^^^ help: try: `core::ptr::null::<usize>()` @@ -11,13 +11,13 @@ LL | #![deny(clippy::zero_ptr)] | ^^^^^^^^^^^^^^^^ error: `0 as *mut _` detected - --> tests/ui/zero_ptr_no_std.rs:8:13 + --> tests/ui/zero_ptr_no_std.rs:7:13 | LL | let _ = 0 as *mut f64; | ^^^^^^^^^^^^^ help: try: `core::ptr::null_mut::<f64>()` error: `0 as *const _` detected - --> tests/ui/zero_ptr_no_std.rs:9:24 + --> tests/ui/zero_ptr_no_std.rs:8:24 | LL | let _: *const u8 = 0 as *const _; | ^^^^^^^^^^^^^ help: try: `core::ptr::null()` diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 16cc1d2a565..4f8e475e762 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -34,7 +34,7 @@ libc = "0.2" miow = "0.6" [target.'cfg(windows)'.dependencies.windows] -version = "0.57.0" +version = "0.59.0" features = [ "Win32_Foundation", "Win32_System_Diagnostics_Debug", diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs index 01068af3e8c..5784cd83119 100644 --- a/src/tools/compiletest/src/directive-list.rs +++ b/src/tools/compiletest/src/directive-list.rs @@ -175,6 +175,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[ "only-beta", "only-bpf", "only-cdb", + "only-dist", "only-gnu", "only-i686-pc-windows-gnu", "only-i686-pc-windows-msvc", diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs index efe758e65cf..37ef63ae42e 100644 --- a/src/tools/compiletest/src/errors.rs +++ b/src/tools/compiletest/src/errors.rs @@ -101,6 +101,8 @@ pub fn load_errors(testfile: &Path, revision: Option<&str>) -> Vec<Error> { rdr.lines() .enumerate() + // We want to ignore utf-8 failures in tests during collection of annotations. + .filter(|(_, line)| line.is_ok()) .filter_map(|(line_num, line)| { parse_expected(last_nonfollow_error, line_num + 1, &line.unwrap(), revision).map( |(which, error)| { diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index 3f7225195ce..6e5ced17c20 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -235,6 +235,12 @@ fn parse_cfg_name_directive<'a>( message: "when the test mode is {name}", } + condition! { + name: "dist", + condition: std::env::var("COMPILETEST_ENABLE_DIST_TESTS") == Ok("1".to_string()), + message: "when performing tests on dist toolchain" + } + if prefix == "ignore" && outcome == MatchOutcome::Invalid { // Don't error out for ignore-tidy-* diretives, as those are not handled by compiletest. if name.starts_with("tidy-") { diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 84f2149dbdf..ca48abda5fc 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -59,7 +59,7 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R { use std::sync::Mutex; use windows::Win32::System::Diagnostics::Debug::{ - SEM_FAILCRITICALERRORS, SEM_NOGPFAULTERRORBOX, SetErrorMode, THREAD_ERROR_MODE, + SEM_FAILCRITICALERRORS, SEM_NOGPFAULTERRORBOX, SetErrorMode, }; static LOCK: Mutex<()> = Mutex::new(()); @@ -80,7 +80,6 @@ fn disable_error_reporting<F: FnOnce() -> R, R>(f: F) -> R { unsafe { // read inherited flags let old_mode = SetErrorMode(SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS); - let old_mode = THREAD_ERROR_MODE(old_mode); SetErrorMode(old_mode | SEM_NOGPFAULTERRORBOX | SEM_FAILCRITICALERRORS); let r = f(); SetErrorMode(old_mode); diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 570b2c374c0..19340b5d07a 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -50,6 +50,29 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ ("alloc/slice/trait.Concat.html", &["#method.concat"]), ("alloc/slice/index.html", &["#method.concat", "#method.join"]), ("alloc/vec/struct.Vec.html", &["#method.sort_by_key", "#method.sort_by_cached_key"]), + ("alloc/bstr/struct.ByteStr.html", &[ + "#method.to_ascii_uppercase", + "#method.to_ascii_lowercase", + "core/slice::sort_by_key", + "core\\slice::sort_by_key", + "#method.sort_by_cached_key", + "#method.sort_by_key" + ]), + ("alloc/bstr/struct.ByteString.html", &[ + "#method.to_ascii_uppercase", + "#method.to_ascii_lowercase", + "core/slice::sort_by_key", + "core\\slice::sort_by_key", + "#method.sort_by_cached_key", + "#method.sort_by_key" + ]), + ("core/bstr/struct.ByteStr.html", &[ + "#method.to_ascii_uppercase", + "#method.to_ascii_lowercase", + "core/bstr/slice::sort_by_key", + "core\\bstr\\slice::sort_by_key", + "#method.sort_by_cached_key" + ]), ("core/primitive.str.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase"]), ("core/primitive.slice.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase", "core/slice::sort_by_key", "core\\slice::sort_by_key", diff --git a/src/tools/miri/.github/workflows/ci.yml b/src/tools/miri/.github/workflows/ci.yml index 209fd622202..81df0964d59 100644 --- a/src/tools/miri/.github/workflows/ci.yml +++ b/src/tools/miri/.github/workflows/ci.yml @@ -126,7 +126,7 @@ jobs: with: fetch-depth: 256 # get a bit more of the history - name: install josh-proxy - run: RUSTFLAGS="--cap-lints warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04 + run: cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04 - name: setup bot git name and email run: | git config --global user.name 'The Miri Cronjob Bot' diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md index dd283b7c0a8..5a08ac9af60 100644 --- a/src/tools/miri/CONTRIBUTING.md +++ b/src/tools/miri/CONTRIBUTING.md @@ -290,7 +290,7 @@ We use the [`josh` proxy](https://github.com/josh-project/josh) to transmit chan rustc and Miri repositories. You can install it as follows: ```sh -RUSTFLAGS="--cap-lints=warn" cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r23.12.04 +cargo +stable install josh-proxy --git https://github.com/josh-project/josh --tag r24.10.04 ``` Josh will automatically be started and stopped by `./miri`. diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 9042c5da577..4ae901be9b4 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -217,8 +217,8 @@ degree documented below): - For every other target with OS `linux`, `macos`, or `windows`, Miri should generally work, but we make no promises and we don't run tests for such targets. - We have unofficial support (not maintained by the Miri team itself) for some further operating systems. - - `solaris` / `illumos`: maintained by @devnexen. Supports `std::{env, thread, sync}`, but not `std::fs`. - - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`. + - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite. + - `freebsd`: maintained by @YohDeadfall. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`. - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. - `wasi`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works. - For targets on other operating systems, Miri might fail before even reaching the `main` function. diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh index 0751f86da85..5583030b490 100755 --- a/src/tools/miri/ci/ci.sh +++ b/src/tools/miri/ci/ci.sh @@ -147,13 +147,14 @@ case $HOST_TARGET in # Extra tier 2 TEST_TARGET=arm-unknown-linux-gnueabi run_tests TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice + # Not officially supported tier 2 + TEST_TARGET=x86_64-unknown-illumos run_tests + TEST_TARGET=x86_64-pc-solaris run_tests # Partially supported targets (tier 2) BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator UNIX="hello 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 time hashmap random threadname pthread fs libc-pipe TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe - TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe fs - TEST_TARGET=x86_64-pc-solaris run_tests_minimal $BASIC $UNIX time hashmap random thread sync available-parallelism tls libc-pipe fs TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random sync threadname pthread epoll eventfd TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std diff --git a/src/tools/miri/etc/rust_analyzer_vscode.json b/src/tools/miri/etc/rust_analyzer_vscode.json index 5e51c3e8880..c646953e92b 100644 --- a/src/tools/miri/etc/rust_analyzer_vscode.json +++ b/src/tools/miri/etc/rust_analyzer_vscode.json @@ -5,21 +5,19 @@ "cargo-miri/Cargo.toml", "miri-script/Cargo.toml", ], - "rust-analyzer.check.invocationLocation": "root", "rust-analyzer.check.invocationStrategy": "once", "rust-analyzer.check.overrideCommand": [ - "env", - "MIRI_AUTO_OPS=no", "./miri", "clippy", // make this `check` when working with a locally built rustc "--message-format=json", ], + "rust-analyzer.cargo.extraEnv": { + "MIRI_AUTO_OPS": "no", + "MIRI_IN_RA": "1", + }, // Contrary to what the name suggests, this also affects proc macros. - "rust-analyzer.cargo.buildScripts.invocationLocation": "root", "rust-analyzer.cargo.buildScripts.invocationStrategy": "once", "rust-analyzer.cargo.buildScripts.overrideCommand": [ - "env", - "MIRI_AUTO_OPS=no", "./miri", "check", "--message-format=json", diff --git a/src/tools/miri/miri b/src/tools/miri/miri index ac1a7211c4e..b1b146d7990 100755 --- a/src/tools/miri/miri +++ b/src/tools/miri/miri @@ -3,12 +3,16 @@ set -e # We want to call the binary directly, so we need to know where it ends up. ROOT_DIR="$(dirname "$0")" MIRI_SCRIPT_TARGET_DIR="$ROOT_DIR"/miri-script/target -# If stdout is not a terminal and we are not on CI, assume that we are being invoked by RA, and use JSON output. -if ! [ -t 1 ] && [ -z "$CI" ]; then +TOOLCHAIN="+nightly" +# If we are being invoked for RA, use JSON output and the default toolchain (to make proc-macros +# work in RA). This needs a different target dir to avoid mixing up the builds. +if [ -n "$MIRI_IN_RA" ]; then MESSAGE_FORMAT="--message-format=json" + TOOLCHAIN="" + MIRI_SCRIPT_TARGET_DIR="$MIRI_SCRIPT_TARGET_DIR"/ra fi # We need a nightly toolchain, for `-Zroot-dir`. -cargo +nightly build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \ +cargo $TOOLCHAIN build $CARGO_EXTRA_FLAGS --manifest-path "$ROOT_DIR"/miri-script/Cargo.toml \ -Zroot-dir="$ROOT_DIR" \ -q --target-dir "$MIRI_SCRIPT_TARGET_DIR" $MESSAGE_FORMAT || \ ( echo "Failed to build miri-script. Is the 'nightly' toolchain installed?"; exit 1 ) diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs index 75ac999e8be..17a7c06b525 100644 --- a/src/tools/miri/miri-script/src/commands.rs +++ b/src/tools/miri/miri-script/src/commands.rs @@ -423,7 +423,7 @@ impl Command { .map(|path| path.into_os_string().into_string().unwrap()) .collect() } else { - benches.into_iter().map(Into::into).collect() + benches.into_iter().collect() }; let target_flag = if let Some(target) = target { let mut flag = OsString::from("--target="); @@ -564,6 +564,10 @@ impl Command { if bless { e.sh.set_var("RUSTC_BLESS", "Gesundheit"); } + if e.sh.var("MIRI_TEST_TARGET").is_ok() { + // Avoid trouble due to an incorrectly set env var. + bail!("MIRI_TEST_TARGET must not be set when invoking `./miri test`"); + } if let Some(target) = target { // Tell the harness which target to test. e.sh.set_var("MIRI_TEST_TARGET", target); diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs index a80fed8fcb6..279bdf8cc3f 100644 --- a/src/tools/miri/miri-script/src/main.rs +++ b/src/tools/miri/miri-script/src/main.rs @@ -111,6 +111,7 @@ pub enum Command { /// `rustup-toolchain-install-master` must be installed for this to work. Toolchain { /// Flags that are passed through to `rustup-toolchain-install-master`. + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] flags: Vec<String>, }, /// Pull and merge Miri changes from the rustc repo. diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 24bef6026d4..fa5dbb99e81 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -13170cd787cb733ed24842ee825bcbd98dc01476 +01706e1a34c87656fcbfce198608f4cd2ac6461a diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 9055aa30271..a2e9c63f79e 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -30,10 +30,10 @@ use std::ops::Range; use std::path::PathBuf; use std::str::FromStr; use std::sync::atomic::{AtomicI32, Ordering}; -use std::sync::{Arc, Once}; +use std::sync::Once; use miri::{ - BacktraceStyle, BorrowTrackerMethod, MiriConfig, ProvenanceMode, RetagFields, ValidationMode, + BacktraceStyle, BorrowTrackerMethod, MiriConfig, MiriEntryFnType,ProvenanceMode, RetagFields, ValidationMode, }; use rustc_abi::ExternAbi; use rustc_data_structures::sync; @@ -51,7 +51,7 @@ use rustc_middle::query::LocalCrate; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::util::Providers; -use rustc_session::config::{CrateType, EntryFnType, ErrorOutputType, OptLevel}; +use rustc_session::config::{CrateType, ErrorOutputType, OptLevel}; use rustc_session::search_paths::PathKind; use rustc_session::{CtfeBacktrace, EarlyDiagCtxt}; use rustc_span::def_id::DefId; @@ -73,9 +73,9 @@ impl MiriCompilerCalls { } } -fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) { - if let Some(entry_def) = tcx.entry_fn(()) { - return entry_def; +fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, MiriEntryFnType) { + if let Some((def_id, entry_type)) = tcx.entry_fn(()) { + return (def_id, MiriEntryFnType::Rustc(entry_type)); } // Look for a symbol in the local crate named `miri_start`, and treat that as the entry point. let sym = tcx.exported_symbols(LOCAL_CRATE).iter().find_map(|(sym, _)| { @@ -102,7 +102,7 @@ fn entry_fn(tcx: TyCtxt<'_>) -> (DefId, EntryFnType) { .is_ok(); if correct_func_sig { - (*id, EntryFnType::Start) + (*id, MiriEntryFnType::MiriStart) } else { tcx.dcx().fatal( "`miri_start` must have the following signature:\n\ @@ -370,13 +370,10 @@ fn init_late_loggers(early_dcx: &EarlyDiagCtxt, tcx: TyCtxt<'_>) { fn run_compiler_and_exit( args: &[String], callbacks: &mut (dyn rustc_driver::Callbacks + Send), - using_internal_features: Arc<std::sync::atomic::AtomicBool>, ) -> ! { // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { - rustc_driver::RunCompiler::new(args, callbacks) - .set_using_internal_features(using_internal_features) - .run(); + rustc_driver::run_compiler(args, callbacks); Ok(()) }); std::process::exit(exit_code) @@ -467,8 +464,7 @@ fn main() { // If the environment asks us to actually be rustc, then do that. if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { // Earliest rustc setup. - let using_internal_features = - rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ()); + rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ()); rustc_driver::init_rustc_env_logger(&early_dcx); let target_crate = if crate_kind == "target" { @@ -492,16 +488,11 @@ fn main() { } // We cannot use `rustc_driver::main` as we want it to use `args` as the CLI arguments. - run_compiler_and_exit( - &args, - &mut MiriBeRustCompilerCalls { target_crate }, - using_internal_features, - ) + run_compiler_and_exit(&args, &mut MiriBeRustCompilerCalls { target_crate }) } // Add an ICE bug report hook. - let using_internal_features = - rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ()); + rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ()); // Init loggers the Miri way. init_early_loggers(&early_dcx); @@ -735,9 +726,5 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler_and_exit( - &rustc_args, - &mut MiriCompilerCalls::new(miri_config, many_seeds), - using_internal_features, - ) + run_compiler_and_exit(&rustc_args, &mut MiriCompilerCalls::new(miri_config, many_seeds)) } diff --git a/src/tools/miri/src/concurrency/cpu_affinity.rs b/src/tools/miri/src/concurrency/cpu_affinity.rs index 4e6bca93c5a..b47b614cf5f 100644 --- a/src/tools/miri/src/concurrency/cpu_affinity.rs +++ b/src/tools/miri/src/concurrency/cpu_affinity.rs @@ -54,8 +54,8 @@ impl CpuAffinityMask { let chunk = self.0[start..].first_chunk_mut::<4>().unwrap(); let offset = cpu % 32; *chunk = match target.options.endian { - Endian::Little => (u32::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(), - Endian::Big => (u32::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(), + Endian::Little => (u32::from_le_bytes(*chunk) | (1 << offset)).to_le_bytes(), + Endian::Big => (u32::from_be_bytes(*chunk) | (1 << offset)).to_be_bytes(), }; } 8 => { @@ -63,8 +63,8 @@ impl CpuAffinityMask { let chunk = self.0[start..].first_chunk_mut::<8>().unwrap(); let offset = cpu % 64; *chunk = match target.options.endian { - Endian::Little => (u64::from_le_bytes(*chunk) | 1 << offset).to_le_bytes(), - Endian::Big => (u64::from_be_bytes(*chunk) | 1 << offset).to_be_bytes(), + Endian::Little => (u64::from_le_bytes(*chunk) | (1 << offset)).to_le_bytes(), + Endian::Big => (u64::from_be_bytes(*chunk) | (1 << offset)).to_be_bytes(), }; } other => bug!("chunk size not supported: {other}"), diff --git a/src/tools/miri/src/concurrency/sync.rs b/src/tools/miri/src/concurrency/sync.rs index ef4034cc0c1..14c72e9398a 100644 --- a/src/tools/miri/src/concurrency/sync.rs +++ b/src/tools/miri/src/concurrency/sync.rs @@ -422,7 +422,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { mutex_ref: MutexRef, retval_dest: Option<(Scalar, MPlaceTy<'tcx>)>, } - @unblock = |this| { + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); + assert!(!this.mutex_is_locked(&mutex_ref)); this.mutex_lock(&mutex_ref); @@ -538,7 +540,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { retval: Scalar, dest: MPlaceTy<'tcx>, } - @unblock = |this| { + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); this.rwlock_reader_lock(id); this.write_scalar(retval, &dest)?; interp_ok(()) @@ -623,7 +626,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { retval: Scalar, dest: MPlaceTy<'tcx>, } - @unblock = |this| { + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); this.rwlock_writer_lock(id); this.write_scalar(retval, &dest)?; interp_ok(()) @@ -677,25 +681,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { retval_timeout: Scalar, dest: MPlaceTy<'tcx>, } - @unblock = |this| { - // The condvar was signaled. Make sure we get the clock for that. - if let Some(data_race) = &this.machine.data_race { - data_race.acquire_clock( - &this.machine.sync.condvars[condvar].clock, - &this.machine.threads, - ); + |this, unblock: UnblockKind| { + match unblock { + UnblockKind::Ready => { + // The condvar was signaled. Make sure we get the clock for that. + if let Some(data_race) = &this.machine.data_race { + data_race.acquire_clock( + &this.machine.sync.condvars[condvar].clock, + &this.machine.threads, + ); + } + // Try to acquire the mutex. + // The timeout only applies to the first wait (until the signal), not for mutex acquisition. + this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest) + } + UnblockKind::TimedOut => { + // We have to remove the waiter from the queue again. + let thread = this.active_thread(); + let waiters = &mut this.machine.sync.condvars[condvar].waiters; + waiters.retain(|waiter| *waiter != thread); + // Now get back the lock. + this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest) + } } - // Try to acquire the mutex. - // The timeout only applies to the first wait (until the signal), not for mutex acquisition. - this.condvar_reacquire_mutex(&mutex_ref, retval_succ, dest) - } - @timeout = |this| { - // We have to remove the waiter from the queue again. - let thread = this.active_thread(); - let waiters = &mut this.machine.sync.condvars[condvar].waiters; - waiters.retain(|waiter| *waiter != thread); - // Now get back the lock. - this.condvar_reacquire_mutex(&mutex_ref, retval_timeout, dest) } ), ); @@ -752,25 +760,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { dest: MPlaceTy<'tcx>, errno_timeout: IoError, } - @unblock = |this| { - let futex = futex_ref.0.borrow(); - // Acquire the clock of the futex. - if let Some(data_race) = &this.machine.data_race { - data_race.acquire_clock(&futex.clock, &this.machine.threads); + |this, unblock: UnblockKind| { + match unblock { + UnblockKind::Ready => { + let futex = futex_ref.0.borrow(); + // Acquire the clock of the futex. + if let Some(data_race) = &this.machine.data_race { + data_race.acquire_clock(&futex.clock, &this.machine.threads); + } + // Write the return value. + this.write_scalar(retval_succ, &dest)?; + interp_ok(()) + }, + UnblockKind::TimedOut => { + // Remove the waiter from the futex. + let thread = this.active_thread(); + let mut futex = futex_ref.0.borrow_mut(); + futex.waiters.retain(|waiter| waiter.thread != thread); + // Set errno and write return value. + this.set_last_error(errno_timeout)?; + this.write_scalar(retval_timeout, &dest)?; + interp_ok(()) + }, } - // Write the return value. - this.write_scalar(retval_succ, &dest)?; - interp_ok(()) - } - @timeout = |this| { - // Remove the waiter from the futex. - let thread = this.active_thread(); - let mut futex = futex_ref.0.borrow_mut(); - futex.waiters.retain(|waiter| waiter.thread != thread); - // Set errno and write return value. - this.set_last_error(errno_timeout)?; - this.write_scalar(retval_timeout, &dest)?; - interp_ok(()) } ), ); diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs index 730c27d0160..6d22dd8d68d 100644 --- a/src/tools/miri/src/concurrency/thread.rs +++ b/src/tools/miri/src/concurrency/thread.rs @@ -19,7 +19,7 @@ use crate::concurrency::data_race; use crate::shims::tls; use crate::*; -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq)] enum SchedulingAction { /// Execute step on the active thread. ExecuteStep, @@ -30,6 +30,7 @@ enum SchedulingAction { } /// What to do with TLS allocations from terminated threads +#[derive(Clone, Copy, Debug, PartialEq)] pub enum TlsAllocAction { /// Deallocate backing memory of thread-local statics as usual Deallocate, @@ -38,71 +39,18 @@ pub enum TlsAllocAction { Leak, } -/// Trait for callbacks that are executed when a thread gets unblocked. -pub trait UnblockCallback<'tcx>: VisitProvenance { - /// Will be invoked when the thread was unblocked the "regular" way, - /// i.e. whatever event it was blocking on has happened. - fn unblock(self: Box<Self>, ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) -> InterpResult<'tcx>; - - /// Will be invoked when the timeout ellapsed without the event the - /// thread was blocking on having occurred. - fn timeout(self: Box<Self>, _ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>) - -> InterpResult<'tcx>; +/// The argument type for the "unblock" callback, indicating why the thread got unblocked. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum UnblockKind { + /// Operation completed successfully, thread continues normal execution. + Ready, + /// The operation did not complete within its specified duration. + TimedOut, } -pub type DynUnblockCallback<'tcx> = Box<dyn UnblockCallback<'tcx> + 'tcx>; - -#[macro_export] -macro_rules! callback { - ( - @capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? } - @unblock = |$this:ident| $unblock:block - ) => { - callback!( - @capture<$tcx, $($lft),*> { $($name: $type),* } - @unblock = |$this| $unblock - @timeout = |_this| { - unreachable!( - "timeout on a thread that was blocked without a timeout (or someone forgot to overwrite this method)" - ) - } - ) - }; - ( - @capture<$tcx:lifetime $(,)? $($lft:lifetime),*> { $($name:ident: $type:ty),* $(,)? } - @unblock = |$this:ident| $unblock:block - @timeout = |$this_timeout:ident| $timeout:block - ) => {{ - struct Callback<$tcx, $($lft),*> { - $($name: $type,)* - _phantom: std::marker::PhantomData<&$tcx ()>, - } - - impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> { - #[allow(unused_variables)] - fn visit_provenance(&self, visit: &mut VisitWith<'_>) { - $( - self.$name.visit_provenance(visit); - )* - } - } - - impl<$tcx, $($lft),*> UnblockCallback<$tcx> for Callback<$tcx, $($lft),*> { - fn unblock(self: Box<Self>, $this: &mut MiriInterpCx<$tcx>) -> InterpResult<$tcx> { - #[allow(unused_variables)] - let Callback { $($name,)* _phantom } = *self; - $unblock - } - fn timeout(self: Box<Self>, $this_timeout: &mut MiriInterpCx<$tcx>) -> InterpResult<$tcx> { - #[allow(unused_variables)] - let Callback { $($name,)* _phantom } = *self; - $timeout - } - } - - Box::new(Callback { $($name,)* _phantom: std::marker::PhantomData }) - }} -} +/// Type alias for unblock callbacks, i.e. machine callbacks invoked when +/// a thread gets unblocked. +pub type DynUnblockCallback<'tcx> = DynMachineCallback<'tcx, UnblockKind>; /// A thread identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] @@ -656,7 +604,8 @@ impl<'tcx> ThreadManager<'tcx> { @capture<'tcx> { joined_thread_id: ThreadId, } - @unblock = |this| { + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); if let Some(data_race) = &mut this.machine.data_race { data_race.thread_joined(&this.machine.threads, joined_thread_id); } @@ -842,7 +791,7 @@ trait EvalContextPrivExt<'tcx>: MiriInterpCxExt<'tcx> { // 2. Make the scheduler the only place that can change the active // thread. let old_thread = this.machine.threads.set_active_thread_id(thread); - callback.timeout(this)?; + callback.call(this, UnblockKind::TimedOut)?; this.machine.threads.set_active_thread_id(old_thread); } // found_callback can remain None if the computer's clock @@ -1084,7 +1033,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; // The callback must be executed in the previously blocked thread. let old_thread = this.machine.threads.set_active_thread_id(thread); - callback.unblock(this)?; + callback.call(this, UnblockKind::Ready)?; this.machine.threads.set_active_thread_id(old_thread); interp_ok(()) } diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs index eaf4b30c660..c8f04e25207 100644 --- a/src/tools/miri/src/eval.rs +++ b/src/tools/miri/src/eval.rs @@ -19,6 +19,12 @@ use crate::diagnostics::report_leaks; use crate::shims::tls; use crate::*; +#[derive(Copy, Clone, Debug)] +pub enum MiriEntryFnType { + MiriStart, + Rustc(EntryFnType), +} + /// When the main thread would exit, we will yield to any other thread that is ready to execute. /// But we must only do that a finite number of times, or a background thread running `loop {}` /// will hang the program. @@ -272,7 +278,7 @@ impl<'tcx> MainThreadState<'tcx> { pub fn create_ecx<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, - entry_type: EntryFnType, + entry_type: MiriEntryFnType, config: &MiriConfig, ) -> InterpResult<'tcx, InterpCx<'tcx, MiriMachine<'tcx>>> { let typing_env = ty::TypingEnv::fully_monomorphized(); @@ -300,7 +306,7 @@ pub fn create_ecx<'tcx>( // Setup first stack frame. let entry_instance = ty::Instance::mono(tcx, entry_id); - // First argument is constructed later, because it's skipped if the entry function uses #[start]. + // First argument is constructed later, because it's skipped for `miri_start.` // Second argument (argc): length of `config.args`. let argc = @@ -373,11 +379,9 @@ pub fn create_ecx<'tcx>( // Call start function. match entry_type { - EntryFnType::Main { .. } => { + MiriEntryFnType::Rustc(EntryFnType::Main { .. }) => { let start_id = tcx.lang_items().start_fn().unwrap_or_else(|| { - tcx.dcx().fatal( - "could not find start function. Make sure the entry point is marked with `#[start]`." - ); + tcx.dcx().fatal("could not find start lang item"); }); let main_ret_ty = tcx.fn_sig(entry_id).no_bound_vars().unwrap().output(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); @@ -413,7 +417,7 @@ pub fn create_ecx<'tcx>( StackPopCleanup::Root { cleanup: true }, )?; } - EntryFnType::Start => { + MiriEntryFnType::MiriStart => { ecx.call_function( entry_instance, ExternAbi::Rust, @@ -434,7 +438,7 @@ pub fn create_ecx<'tcx>( pub fn eval_entry<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, - entry_type: EntryFnType, + entry_type: MiriEntryFnType, config: MiriConfig, ) -> Option<i32> { // Copy setting before we move `config`. diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index adfec33beac..ca8dbdac125 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -262,6 +262,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }) } + /// Helper function to get a `libc` constant as an `u64`. + fn eval_libc_u64(&self, name: &str) -> u64 { + // TODO: Cache the result. + self.eval_libc(name).to_u64().unwrap_or_else(|_err| { + panic!("required libc item has unexpected type (not `u64`): {name}") + }) + } + /// Helper function to get a `windows` constant as a `Scalar`. fn eval_windows(&self, module: &str, name: &str) -> Scalar { self.eval_context_ref().eval_path_scalar(&["std", "sys", "pal", "windows", module, name]) diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index e02d51afcef..2955dc38a8c 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -13,6 +13,8 @@ #![feature(strict_overflow_ops)] #![feature(pointer_is_aligned_to)] #![feature(unqualified_local_imports)] +#![feature(derive_coerce_pointee)] +#![feature(arbitrary_self_types)] // Configure clippy and other lints #![allow( clippy::collapsible_else_if, @@ -126,21 +128,21 @@ pub use crate::concurrency::sync::{ CondvarId, EvalContextExt as _, MutexRef, RwLockId, SynchronizationObjects, }; pub use crate::concurrency::thread::{ - BlockReason, EvalContextExt as _, StackEmptyCallback, ThreadId, ThreadManager, TimeoutAnchor, - TimeoutClock, UnblockCallback, + BlockReason, DynUnblockCallback, EvalContextExt as _, StackEmptyCallback, ThreadId, + ThreadManager, TimeoutAnchor, TimeoutClock, UnblockKind, }; pub use crate::diagnostics::{ EvalContextExt as _, NonHaltingDiagnostic, TerminationInfo, report_error, }; pub use crate::eval::{ - AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, ValidationMode, - create_ecx, eval_entry, + AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, MiriEntryFnType, RejectOpWith, + ValidationMode, create_ecx, eval_entry, }; pub use crate::helpers::{AccessKind, EvalContextExt as _}; pub use crate::intrinsics::EvalContextExt as _; pub use crate::machine::{ - AllocExtra, FrameExtra, MemoryKind, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind, - PrimitiveLayouts, Provenance, ProvenanceExtra, + AllocExtra, DynMachineCallback, FrameExtra, MachineCallback, MemoryKind, MiriInterpCx, + MiriInterpCxExt, MiriMachine, MiriMemoryKind, PrimitiveLayouts, Provenance, ProvenanceExtra, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as _; diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index 5e8f616a37e..845ba484326 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1723,3 +1723,69 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { Cow::Borrowed(ecx.machine.union_data_ranges.entry(ty).or_insert_with(compute_range)) } } + +/// Trait for callbacks handling asynchronous machine operations. +pub trait MachineCallback<'tcx, T>: VisitProvenance { + /// The function to be invoked when the callback is fired. + fn call( + self: Box<Self>, + ecx: &mut InterpCx<'tcx, MiriMachine<'tcx>>, + arg: T, + ) -> InterpResult<'tcx>; +} + +/// Type alias for boxed machine callbacks with generic argument type. +pub type DynMachineCallback<'tcx, T> = Box<dyn MachineCallback<'tcx, T> + 'tcx>; + +/// Creates a `DynMachineCallback`: +/// +/// ```rust +/// callback!( +/// @capture<'tcx> { +/// var1: Ty1, +/// var2: Ty2<'tcx>, +/// } +/// |this, arg: ArgTy| { +/// // Implement the callback here. +/// todo!() +/// } +/// ) +/// ``` +/// +/// All the argument types must implement `VisitProvenance`. +#[macro_export] +macro_rules! callback { + (@capture<$tcx:lifetime $(,)? $($lft:lifetime),*> + { $($name:ident: $type:ty),* $(,)? } + |$this:ident, $arg:ident: $arg_ty:ty| $body:expr $(,)?) => {{ + struct Callback<$tcx, $($lft),*> { + $($name: $type,)* + _phantom: std::marker::PhantomData<&$tcx ()>, + } + + impl<$tcx, $($lft),*> VisitProvenance for Callback<$tcx, $($lft),*> { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + $( + self.$name.visit_provenance(_visit); + )* + } + } + + impl<$tcx, $($lft),*> MachineCallback<$tcx, $arg_ty> for Callback<$tcx, $($lft),*> { + fn call( + self: Box<Self>, + $this: &mut MiriInterpCx<$tcx>, + $arg: $arg_ty + ) -> InterpResult<$tcx> { + #[allow(unused_variables)] + let Callback { $($name,)* _phantom } = *self; + $body + } + } + + Box::new(Callback { + $($name,)* + _phantom: std::marker::PhantomData + }) + }}; +} diff --git a/src/tools/miri/src/shims/files.rs b/src/tools/miri/src/shims/files.rs index f673b834be2..73425eee515 100644 --- a/src/tools/miri/src/shims/files.rs +++ b/src/tools/miri/src/shims/files.rs @@ -1,6 +1,7 @@ use std::any::Any; use std::collections::BTreeMap; use std::io::{IsTerminal, Read, SeekFrom, Write}; +use std::marker::CoercePointee; use std::ops::Deref; use std::rc::{Rc, Weak}; use std::{fs, io}; @@ -10,16 +11,132 @@ use rustc_abi::Size; use crate::shims::unix::UnixFileDescription; use crate::*; +/// A unique id for file descriptions. While we could use the address, considering that +/// is definitely unique, the address would expose interpreter internal state when used +/// for sorting things. So instead we generate a unique id per file description is the name +/// for all `dup`licates and is never reused. +#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)] +pub struct FdId(usize); + +#[derive(Debug, Clone)] +struct FdIdWith<T: ?Sized> { + id: FdId, + inner: T, +} + +/// A refcounted pointer to a file description, also tracking the +/// globally unique ID of this file description. +#[repr(transparent)] +#[derive(CoercePointee, Debug)] +pub struct FileDescriptionRef<T: ?Sized>(Rc<FdIdWith<T>>); + +impl<T: ?Sized> Clone for FileDescriptionRef<T> { + fn clone(&self) -> Self { + FileDescriptionRef(self.0.clone()) + } +} + +impl<T: ?Sized> Deref for FileDescriptionRef<T> { + type Target = T; + fn deref(&self) -> &T { + &self.0.inner + } +} + +impl<T: ?Sized> FileDescriptionRef<T> { + pub fn id(&self) -> FdId { + self.0.id + } +} + +/// Holds a weak reference to the actual file description. +#[derive(Debug)] +pub struct WeakFileDescriptionRef<T: ?Sized>(Weak<FdIdWith<T>>); + +impl<T: ?Sized> Clone for WeakFileDescriptionRef<T> { + fn clone(&self) -> Self { + WeakFileDescriptionRef(self.0.clone()) + } +} + +impl<T: ?Sized> FileDescriptionRef<T> { + pub fn downgrade(this: &Self) -> WeakFileDescriptionRef<T> { + WeakFileDescriptionRef(Rc::downgrade(&this.0)) + } +} + +impl<T: ?Sized> WeakFileDescriptionRef<T> { + pub fn upgrade(&self) -> Option<FileDescriptionRef<T>> { + self.0.upgrade().map(FileDescriptionRef) + } +} + +impl<T> VisitProvenance for WeakFileDescriptionRef<T> { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + // A weak reference can never be the only reference to some pointer or place. + // Since the actual file description is tracked by strong ref somewhere, + // it is ok to make this a NOP operation. + } +} + +/// A helper trait to indirectly allow downcasting on `Rc<FdIdWith<dyn _>>`. +/// Ideally we'd just add a `FdIdWith<Self>: Any` bound to the `FileDescription` trait, +/// but that does not allow upcasting. +pub trait FileDescriptionExt: 'static { + fn into_rc_any(self: FileDescriptionRef<Self>) -> Rc<dyn Any>; + + /// We wrap the regular `close` function generically, so both handle `Rc::into_inner` + /// and epoll interest management. + fn close_ref<'tcx>( + self: FileDescriptionRef<Self>, + communicate_allowed: bool, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>>; +} + +impl<T: FileDescription + 'static> FileDescriptionExt for T { + fn into_rc_any(self: FileDescriptionRef<Self>) -> Rc<dyn Any> { + self.0 + } + + fn close_ref<'tcx>( + self: FileDescriptionRef<Self>, + communicate_allowed: bool, + ecx: &mut MiriInterpCx<'tcx>, + ) -> InterpResult<'tcx, io::Result<()>> { + match Rc::into_inner(self.0) { + Some(fd) => { + // Remove entry from the global epoll_event_interest table. + ecx.machine.epoll_interests.remove(fd.id); + + fd.inner.close(communicate_allowed, ecx) + } + None => { + // Not the last reference. + interp_ok(Ok(())) + } + } + } +} + +pub type DynFileDescriptionRef = FileDescriptionRef<dyn FileDescription>; + +impl FileDescriptionRef<dyn FileDescription> { + pub fn downcast<T: FileDescription + 'static>(self) -> Option<FileDescriptionRef<T>> { + let inner = self.into_rc_any().downcast::<FdIdWith<T>>().ok()?; + Some(FileDescriptionRef(inner)) + } +} + /// Represents an open file description. -pub trait FileDescription: std::fmt::Debug + Any { +pub trait FileDescription: std::fmt::Debug + FileDescriptionExt { fn name(&self) -> &'static str; /// Reads as much as possible into the given buffer `ptr`. /// `len` indicates how many bytes we should try to read. /// `dest` is where the return value should be stored: number of bytes read, or `-1` in case of error. fn read<'tcx>( - &self, - _self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, _communicate_allowed: bool, _ptr: Pointer, _len: usize, @@ -33,8 +150,7 @@ pub trait FileDescription: std::fmt::Debug + Any { /// `len` indicates how many bytes we should try to write. /// `dest` is where the return value should be stored: number of bytes written, or `-1` in case of error. fn write<'tcx>( - &self, - _self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, _communicate_allowed: bool, _ptr: Pointer, _len: usize, @@ -54,11 +170,15 @@ pub trait FileDescription: std::fmt::Debug + Any { throw_unsup_format!("cannot seek on {}", self.name()); } + /// Close the file descriptor. fn close<'tcx>( - self: Box<Self>, + self, _communicate_allowed: bool, _ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result<()>> { + ) -> InterpResult<'tcx, io::Result<()>> + where + Self: Sized, + { throw_unsup_format!("cannot close {}", self.name()); } @@ -77,21 +197,13 @@ pub trait FileDescription: std::fmt::Debug + Any { } } -impl dyn FileDescription { - #[inline(always)] - pub fn downcast<T: Any>(&self) -> Option<&T> { - (self as &dyn Any).downcast_ref() - } -} - impl FileDescription for io::Stdin { fn name(&self) -> &'static str { "stdin" } fn read<'tcx>( - &self, - _self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, communicate_allowed: bool, ptr: Pointer, len: usize, @@ -103,7 +215,7 @@ impl FileDescription for io::Stdin { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. helpers::isolation_abort_error("`read` from stdin")?; } - let result = Read::read(&mut { self }, &mut bytes); + let result = Read::read(&mut &*self, &mut bytes); match result { Ok(read_size) => ecx.return_read_success(ptr, &bytes, read_size, dest), Err(e) => ecx.set_last_error_and_return(e, dest), @@ -121,8 +233,7 @@ impl FileDescription for io::Stdout { } fn write<'tcx>( - &self, - _self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, _communicate_allowed: bool, ptr: Pointer, len: usize, @@ -131,7 +242,7 @@ impl FileDescription for io::Stdout { ) -> InterpResult<'tcx> { let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; // We allow writing to stderr even with isolation enabled. - let result = Write::write(&mut { self }, bytes); + let result = Write::write(&mut &*self, bytes); // Stdout is buffered, flush to make sure it appears on the // screen. This is the write() syscall of the interpreted // program, we want it to correspond to a write() syscall on @@ -155,8 +266,7 @@ impl FileDescription for io::Stderr { } fn write<'tcx>( - &self, - _self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, _communicate_allowed: bool, ptr: Pointer, len: usize, @@ -166,7 +276,7 @@ impl FileDescription for io::Stderr { let bytes = ecx.read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(len))?; // We allow writing to stderr even with isolation enabled. // No need to flush, stderr is not buffered. - let result = Write::write(&mut { self }, bytes); + let result = Write::write(&mut &*self, bytes); match result { Ok(write_size) => ecx.return_write_success(write_size, dest), Err(e) => ecx.set_last_error_and_return(e, dest), @@ -188,8 +298,7 @@ impl FileDescription for NullOutput { } fn write<'tcx>( - &self, - _self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, _communicate_allowed: bool, _ptr: Pointer, len: usize, @@ -201,91 +310,10 @@ impl FileDescription for NullOutput { } } -/// Structure contains both the file description and its unique identifier. -#[derive(Clone, Debug)] -pub struct FileDescWithId<T: FileDescription + ?Sized> { - id: FdId, - file_description: Box<T>, -} - -#[derive(Clone, Debug)] -pub struct FileDescriptionRef(Rc<FileDescWithId<dyn FileDescription>>); - -impl Deref for FileDescriptionRef { - type Target = dyn FileDescription; - - fn deref(&self) -> &Self::Target { - &*self.0.file_description - } -} - -impl FileDescriptionRef { - fn new(fd: impl FileDescription, id: FdId) -> Self { - FileDescriptionRef(Rc::new(FileDescWithId { id, file_description: Box::new(fd) })) - } - - pub fn close<'tcx>( - self, - communicate_allowed: bool, - ecx: &mut MiriInterpCx<'tcx>, - ) -> InterpResult<'tcx, io::Result<()>> { - // Destroy this `Rc` using `into_inner` so we can call `close` instead of - // implicitly running the destructor of the file description. - let id = self.get_id(); - match Rc::into_inner(self.0) { - Some(fd) => { - // Remove entry from the global epoll_event_interest table. - ecx.machine.epoll_interests.remove(id); - - fd.file_description.close(communicate_allowed, ecx) - } - None => interp_ok(Ok(())), - } - } - - pub fn downgrade(&self) -> WeakFileDescriptionRef { - WeakFileDescriptionRef { weak_ref: Rc::downgrade(&self.0) } - } - - pub fn get_id(&self) -> FdId { - self.0.id - } -} - -/// Holds a weak reference to the actual file description. -#[derive(Clone, Debug, Default)] -pub struct WeakFileDescriptionRef { - weak_ref: Weak<FileDescWithId<dyn FileDescription>>, -} - -impl WeakFileDescriptionRef { - pub fn upgrade(&self) -> Option<FileDescriptionRef> { - if let Some(file_desc_with_id) = self.weak_ref.upgrade() { - return Some(FileDescriptionRef(file_desc_with_id)); - } - None - } -} - -impl VisitProvenance for WeakFileDescriptionRef { - fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { - // A weak reference can never be the only reference to some pointer or place. - // Since the actual file description is tracked by strong ref somewhere, - // it is ok to make this a NOP operation. - } -} - -/// A unique id for file descriptions. While we could use the address, considering that -/// is definitely unique, the address would expose interpreter internal state when used -/// for sorting things. So instead we generate a unique id per file description is the name -/// for all `dup`licates and is never reused. -#[derive(Debug, Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd)] -pub struct FdId(usize); - /// The file descriptor table #[derive(Debug)] pub struct FdTable { - pub fds: BTreeMap<i32, FileDescriptionRef>, + pub fds: BTreeMap<i32, DynFileDescriptionRef>, /// Unique identifier for file description, used to differentiate between various file description. next_file_description_id: FdId, } @@ -313,8 +341,9 @@ impl FdTable { fds } - pub fn new_ref(&mut self, fd: impl FileDescription) -> FileDescriptionRef { - let file_handle = FileDescriptionRef::new(fd, self.next_file_description_id); + pub fn new_ref<T: FileDescription>(&mut self, fd: T) -> FileDescriptionRef<T> { + let file_handle = + FileDescriptionRef(Rc::new(FdIdWith { id: self.next_file_description_id, inner: fd })); self.next_file_description_id = FdId(self.next_file_description_id.0.strict_add(1)); file_handle } @@ -325,12 +354,16 @@ impl FdTable { self.insert(fd_ref) } - pub fn insert(&mut self, fd_ref: FileDescriptionRef) -> i32 { + pub fn insert(&mut self, fd_ref: DynFileDescriptionRef) -> i32 { self.insert_with_min_num(fd_ref, 0) } /// Insert a file description, giving it a file descriptor that is at least `min_fd_num`. - pub fn insert_with_min_num(&mut self, file_handle: FileDescriptionRef, min_fd_num: i32) -> i32 { + pub fn insert_with_min_num( + &mut self, + file_handle: DynFileDescriptionRef, + min_fd_num: i32, + ) -> i32 { // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in // between used FDs, the find_map combinator will return it. If the first such unused FD // is after all other used FDs, the find_map combinator will return None, and we will use @@ -356,12 +389,12 @@ impl FdTable { new_fd_num } - pub fn get(&self, fd_num: i32) -> Option<FileDescriptionRef> { + pub fn get(&self, fd_num: i32) -> Option<DynFileDescriptionRef> { let fd = self.fds.get(&fd_num)?; Some(fd.clone()) } - pub fn remove(&mut self, fd_num: i32) -> Option<FileDescriptionRef> { + pub fn remove(&mut self, fd_num: i32) -> Option<DynFileDescriptionRef> { self.fds.remove(&fd_num) } diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs index 87be5a521d1..8c9e1860f31 100644 --- a/src/tools/miri/src/shims/native_lib.rs +++ b/src/tools/miri/src/shims/native_lib.rs @@ -72,7 +72,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { } // Functions with no declared return type (i.e., the default return) // have the output_type `Tuple([])`. - ty::Tuple(t_list) if t_list.len() == 0 => { + ty::Tuple(t_list) if t_list.is_empty() => { unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) }; return interp_ok(ImmTy::uninit(dest.layout)); } diff --git a/src/tools/miri/src/shims/time.rs b/src/tools/miri/src/shims/time.rs index 72d98bc1c48..d6c77d9c4d9 100644 --- a/src/tools/miri/src/shims/time.rs +++ b/src/tools/miri/src/shims/time.rs @@ -331,8 +331,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)), callback!( @capture<'tcx> {} - @unblock = |_this| { panic!("sleeping thread unblocked before time is up") } - @timeout = |_this| { interp_ok(()) } + |_this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::TimedOut); + interp_ok(()) + } ), ); interp_ok(Scalar::from_i32(0)) @@ -353,8 +355,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { Some((TimeoutClock::Monotonic, TimeoutAnchor::Relative, duration)), callback!( @capture<'tcx> {} - @unblock = |_this| { panic!("sleeping thread unblocked before time is up") } - @timeout = |_this| { interp_ok(()) } + |_this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::TimedOut); + interp_ok(()) + } ), ); interp_ok(()) diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs index e5dead1a263..0b59490308b 100644 --- a/src/tools/miri/src/shims/unix/fd.rs +++ b/src/tools/miri/src/shims/unix/fd.rs @@ -88,7 +88,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // If old_fd and new_fd point to the same description, then `dup_fd` ensures we keep the underlying file description alive. if let Some(old_new_fd) = this.machine.fds.fds.insert(new_fd_num, fd) { // Ignore close error (not interpreter's) according to dup2() doc. - old_new_fd.close(this.machine.communicate(), this)?.ok(); + old_new_fd.close_ref(this.machine.communicate(), this)?.ok(); } } interp_ok(Scalar::from_i32(new_fd_num)) @@ -122,7 +122,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; let result = fd.as_unix().flock(this.machine.communicate(), parsed_op)?; - drop(fd); // return `0` if flock is successful let result = result.map(|()| 0i32); interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) @@ -198,7 +197,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Some(fd) = this.machine.fds.remove(fd_num) else { return this.set_last_error_and_return_i32(LibcError("EBADF")); }; - let result = fd.close(this.machine.communicate(), this)?; + let result = fd.close_ref(this.machine.communicate(), this)?; // return `0` if close is successful let result = result.map(|()| 0i32); interp_ok(Scalar::from_i32(this.try_unwrap_io_result(result)?)) @@ -246,7 +245,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // `usize::MAX` because it is bounded by the host's `isize`. match offset { - None => fd.read(&fd, communicate, buf, count, dest, this)?, + None => fd.read(communicate, buf, count, dest, this)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { return this.set_last_error_and_return(LibcError("EINVAL"), dest); @@ -286,7 +285,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; match offset { - None => fd.write(&fd, communicate, buf, count, dest, this)?, + None => fd.write(communicate, buf, count, dest, this)?, Some(offset) => { let Ok(offset) = u64::try_from(offset) else { return this.set_last_error_and_return(LibcError("EINVAL"), dest); diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs index f47a96b10fe..3353cf2cc59 100644 --- a/src/tools/miri/src/shims/unix/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/foreign_items.rs @@ -109,56 +109,54 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); // See `fn emulate_foreign_item_inner` in `shims/foreign_items.rs` for the general pattern. - #[rustfmt::skip] match link_name.as_str() { // Environment related shims "getenv" => { - let [name] = this.check_shim(abi, Conv::C , link_name, args)?; + let [name] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.getenv(name)?; this.write_pointer(result, dest)?; } "unsetenv" => { - let [name] = this.check_shim(abi, Conv::C , link_name, args)?; + let [name] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.unsetenv(name)?; this.write_scalar(result, dest)?; } "setenv" => { - let [name, value, overwrite] = this.check_shim(abi, Conv::C , link_name, args)?; + let [name, value, overwrite] = this.check_shim(abi, Conv::C, link_name, args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(result, dest)?; } "getcwd" => { - let [buf, size] = this.check_shim(abi, Conv::C , link_name, args)?; + let [buf, size] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.getcwd(buf, size)?; this.write_pointer(result, dest)?; } "chdir" => { - let [path] = this.check_shim(abi, Conv::C , link_name, args)?; + let [path] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.chdir(path)?; this.write_scalar(result, dest)?; } "getpid" => { - let [] = this.check_shim(abi, Conv::C , link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.getpid()?; this.write_scalar(result, dest)?; } "sysconf" => { - let [val] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [val] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.sysconf(val)?; this.write_scalar(result, dest)?; } // File descriptors "read" => { - let [fd, buf, count] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, buf, count] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; this.read(fd, buf, count, None, dest)?; } "write" => { - let [fd, buf, n] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, buf, n] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; @@ -166,7 +164,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write(fd, buf, count, None, dest)?; } "pread" => { - let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; @@ -174,7 +172,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.read(fd, buf, count, Some(offset), dest)?; } "pwrite" => { - let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; @@ -183,49 +181,51 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write(fd, buf, count, Some(offset), dest)?; } "pread64" => { - let [fd, buf, count, offset] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, buf, count, offset] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(count)?; - let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; + let offset = + this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; this.read(fd, buf, count, Some(offset), dest)?; } "pwrite64" => { - let [fd, buf, n, offset] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, buf, n, offset] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_target_usize(n)?; - let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; + let offset = + this.read_scalar(offset)?.to_int(this.libc_ty_layout("off64_t").size)?; trace!("Called pwrite64({:?}, {:?}, {:?}, {:?})", fd, buf, count, offset); this.write(fd, buf, count, Some(offset), dest)?; } "close" => { - let [fd] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.close(fd)?; this.write_scalar(result, dest)?; } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument // in `this.fcntl()`, so we do not use `check_shim` here. - this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?; + this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; let result = this.fcntl(args)?; this.write_scalar(result, dest)?; } "dup" => { - let [old_fd] = this.check_shim(abi, Conv::C , link_name, args)?; + let [old_fd] = this.check_shim(abi, Conv::C, link_name, args)?; let old_fd = this.read_scalar(old_fd)?.to_i32()?; let new_fd = this.dup(old_fd)?; this.write_scalar(new_fd, dest)?; } "dup2" => { - let [old_fd, new_fd] = this.check_shim(abi, Conv::C , link_name, args)?; + let [old_fd, new_fd] = this.check_shim(abi, Conv::C, link_name, args)?; let old_fd = this.read_scalar(old_fd)?.to_i32()?; let new_fd = this.read_scalar(new_fd)?.to_i32()?; let result = this.dup2(old_fd, new_fd)?; this.write_scalar(result, dest)?; } "flock" => { - let [fd, op] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, op] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let op = this.read_scalar(op)?.to_i32()?; let result = this.flock(fd, op)?; @@ -234,48 +234,49 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // File and file system access "open" | "open64" => { - // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set - this.check_abi_and_shim_symbol_clash(abi, Conv::C , link_name)?; + // `open` is variadic, the third argument is only present when the second argument + // has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set + this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; let result = this.open(args)?; this.write_scalar(result, dest)?; } "unlink" => { - let [path] = this.check_shim(abi, Conv::C , link_name, args)?; + let [path] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.unlink(path)?; this.write_scalar(result, dest)?; } "symlink" => { - let [target, linkpath] = this.check_shim(abi, Conv::C , link_name, args)?; + let [target, linkpath] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(result, dest)?; } "rename" => { - let [oldpath, newpath] = this.check_shim(abi, Conv::C , link_name, args)?; + let [oldpath, newpath] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(result, dest)?; } "mkdir" => { - let [path, mode] = this.check_shim(abi, Conv::C , link_name, args)?; + let [path, mode] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.mkdir(path, mode)?; this.write_scalar(result, dest)?; } "rmdir" => { - let [path] = this.check_shim(abi, Conv::C , link_name, args)?; + let [path] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.rmdir(path)?; this.write_scalar(result, dest)?; } "opendir" => { - let [name] = this.check_shim(abi, Conv::C , link_name, args)?; + let [name] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "closedir" => { - let [dirp] = this.check_shim(abi, Conv::C , link_name, args)?; + let [dirp] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.closedir(dirp)?; this.write_scalar(result, dest)?; } "lseek64" => { - let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let offset = this.read_scalar(offset)?.to_i64()?; let whence = this.read_scalar(whence)?.to_i32()?; @@ -283,7 +284,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "lseek" => { - let [fd, offset, whence] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, offset, whence] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; let whence = this.read_scalar(whence)?.to_i32()?; @@ -291,39 +292,36 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } "ftruncate64" => { - let [fd, length] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let length = this.read_scalar(length)?.to_i64()?; let result = this.ftruncate64(fd, length.into())?; this.write_scalar(result, dest)?; } "ftruncate" => { - let [fd, length] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, length] = this.check_shim(abi, Conv::C, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let length = this.read_scalar(length)?.to_int(this.libc_ty_layout("off_t").size)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(result, dest)?; } "fsync" => { - let [fd] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.fsync(fd)?; this.write_scalar(result, dest)?; } "fdatasync" => { - let [fd] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.fdatasync(fd)?; this.write_scalar(result, dest)?; } "readlink" => { - let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C , link_name, args)?; + let [pathname, buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_target_isize(result, this), dest)?; } "posix_fadvise" => { - let [fd, offset, len, advice] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [fd, offset, len, advice] = this.check_shim(abi, Conv::C, link_name, args)?; this.read_scalar(fd)?.to_i32()?; this.read_target_isize(offset)?; this.read_target_isize(len)?; @@ -332,12 +330,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "realpath" => { - let [path, resolved_path] = this.check_shim(abi, Conv::C , link_name, args)?; + let [path, resolved_path] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.realpath(path, resolved_path)?; this.write_scalar(result, dest)?; } "mkstemp" => { - let [template] = this.check_shim(abi, Conv::C , link_name, args)?; + let [template] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.mkstemp(template)?; this.write_scalar(result, dest)?; } @@ -345,63 +343,59 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Unnamed sockets and pipes "socketpair" => { let [domain, type_, protocol, sv] = - this.check_shim(abi, Conv::C , link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; let result = this.socketpair(domain, type_, protocol, sv)?; this.write_scalar(result, dest)?; } "pipe" => { - let [pipefd] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [pipefd] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.pipe2(pipefd, /*flags*/ None)?; this.write_scalar(result, dest)?; } "pipe2" => { // Currently this function does not exist on all Unixes, e.g. on macOS. - if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "solaris" | "illumos") { - throw_unsup_format!( - "`pipe2` is not supported on {}", - this.tcx.sess.target.os - ); + if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "solaris" | "illumos") + { + throw_unsup_format!("`pipe2` is not supported on {}", this.tcx.sess.target.os); } - let [pipefd, flags] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [pipefd, flags] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.pipe2(pipefd, Some(flags))?; this.write_scalar(result, dest)?; } // Time "gettimeofday" => { - let [tv, tz] = this.check_shim(abi, Conv::C , link_name, args)?; + let [tv, tz] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(result, dest)?; } "localtime_r" => { - let [timep, result_op] = this.check_shim(abi, Conv::C , link_name, args)?; + let [timep, result_op] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.localtime_r(timep, result_op)?; this.write_pointer(result, dest)?; } "clock_gettime" => { - let [clk_id, tp] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [clk_id, tp] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(result, dest)?; } // Allocation "posix_memalign" => { - let [memptr, align, size] = this.check_shim(abi, Conv::C , link_name, args)?; + let [memptr, align, size] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.posix_memalign(memptr, align, size)?; this.write_scalar(result, dest)?; } "mmap" => { - let [addr, length, prot, flags, fd, offset] = this.check_shim(abi, Conv::C , link_name, args)?; + let [addr, length, prot, flags, fd, offset] = + this.check_shim(abi, Conv::C, link_name, args)?; let offset = this.read_scalar(offset)?.to_int(this.libc_ty_layout("off_t").size)?; let ptr = this.mmap(addr, length, prot, flags, fd, offset)?; this.write_scalar(ptr, dest)?; } "munmap" => { - let [addr, length] = this.check_shim(abi, Conv::C , link_name, args)?; + let [addr, length] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.munmap(addr, length)?; this.write_scalar(result, dest)?; } @@ -414,8 +408,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.tcx.sess.target.os ); } - let [ptr, nmemb, size] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr, nmemb, size] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let nmemb = this.read_target_usize(nmemb)?; let size = this.read_target_usize(size)?; @@ -438,19 +431,20 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "aligned_alloc" => { // This is a C11 function, we assume all Unixes have it. // (MSVC explicitly does not support this.) - let [align, size] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [align, size] = this.check_shim(abi, Conv::C, link_name, args)?; let res = this.aligned_alloc(align, size)?; this.write_pointer(res, dest)?; } // Dynamic symbol loading "dlsym" => { - let [handle, symbol] = this.check_shim(abi, Conv::C , link_name, args)?; + let [handle, symbol] = this.check_shim(abi, Conv::C, link_name, args)?; this.read_target_usize(handle)?; let symbol = this.read_pointer(symbol)?; let name = this.read_c_str(symbol)?; - if let Ok(name) = str::from_utf8(name) && is_dyn_sym(name, &this.tcx.sess.target.os) { + if let Ok(name) = str::from_utf8(name) + && is_dyn_sym(name, &this.tcx.sess.target.os) + { let ptr = this.fn_ptr(FnVal::Other(DynSym::from_str(name))); this.write_pointer(ptr, dest)?; } else { @@ -460,7 +454,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Thread-local storage "pthread_key_create" => { - let [key, dtor] = this.check_shim(abi, Conv::C , link_name, args)?; + let [key, dtor] = this.check_shim(abi, Conv::C, link_name, args)?; let key_place = this.deref_pointer_as(key, this.libc_ty_layout("pthread_key_t"))?; let dtor = this.read_pointer(dtor)?; @@ -488,21 +482,21 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } "pthread_key_delete" => { - let [key] = this.check_shim(abi, Conv::C , link_name, args)?; + let [key] = this.check_shim(abi, Conv::C, link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let [key] = this.check_shim(abi, Conv::C , link_name, args)?; + let [key] = this.check_shim(abi, Conv::C, link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let [key, new_ptr] = this.check_shim(abi, Conv::C , link_name, args)?; + let [key, new_ptr] = this.check_shim(abi, Conv::C, link_name, args)?; let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.active_thread(); let new_data = this.read_scalar(new_ptr)?; @@ -514,151 +508,149 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Synchronization primitives "pthread_mutexattr_init" => { - let [attr] = this.check_shim(abi, Conv::C , link_name, args)?; + let [attr] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_mutexattr_init(attr)?; this.write_null(dest)?; } "pthread_mutexattr_settype" => { - let [attr, kind] = this.check_shim(abi, Conv::C , link_name, args)?; + let [attr, kind] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(result, dest)?; } "pthread_mutexattr_destroy" => { - let [attr] = this.check_shim(abi, Conv::C , link_name, args)?; + let [attr] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_mutexattr_destroy(attr)?; this.write_null(dest)?; } "pthread_mutex_init" => { - let [mutex, attr] = this.check_shim(abi, Conv::C , link_name, args)?; + let [mutex, attr] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_mutex_init(mutex, attr)?; this.write_null(dest)?; } "pthread_mutex_lock" => { - let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?; + let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_mutex_lock(mutex, dest)?; } "pthread_mutex_trylock" => { - let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?; + let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(result, dest)?; } "pthread_mutex_unlock" => { - let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?; + let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(result, dest)?; } "pthread_mutex_destroy" => { - let [mutex] = this.check_shim(abi, Conv::C , link_name, args)?; + let [mutex] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_mutex_destroy(mutex)?; this.write_int(0, dest)?; } "pthread_rwlock_rdlock" => { - let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_rwlock_rdlock(rwlock, dest)?; } "pthread_rwlock_tryrdlock" => { - let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(result, dest)?; } "pthread_rwlock_wrlock" => { - let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_rwlock_wrlock(rwlock, dest)?; } "pthread_rwlock_trywrlock" => { - let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(result, dest)?; } "pthread_rwlock_unlock" => { - let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_rwlock_unlock(rwlock)?; this.write_null(dest)?; } "pthread_rwlock_destroy" => { - let [rwlock] = this.check_shim(abi, Conv::C , link_name, args)?; + let [rwlock] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_rwlock_destroy(rwlock)?; this.write_null(dest)?; } "pthread_condattr_init" => { - let [attr] = this.check_shim(abi, Conv::C , link_name, args)?; + let [attr] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_condattr_init(attr)?; this.write_null(dest)?; } "pthread_condattr_setclock" => { - let [attr, clock_id] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(result, dest)?; } "pthread_condattr_getclock" => { - let [attr, clock_id] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [attr, clock_id] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_condattr_getclock(attr, clock_id)?; this.write_null(dest)?; } "pthread_condattr_destroy" => { - let [attr] = this.check_shim(abi, Conv::C , link_name, args)?; + let [attr] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_condattr_destroy(attr)?; this.write_null(dest)?; } "pthread_cond_init" => { - let [cond, attr] = this.check_shim(abi, Conv::C , link_name, args)?; + let [cond, attr] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_cond_init(cond, attr)?; this.write_null(dest)?; } "pthread_cond_signal" => { - let [cond] = this.check_shim(abi, Conv::C , link_name, args)?; + let [cond] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_cond_signal(cond)?; this.write_null(dest)?; } "pthread_cond_broadcast" => { - let [cond] = this.check_shim(abi, Conv::C , link_name, args)?; + let [cond] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_cond_broadcast(cond)?; this.write_null(dest)?; } "pthread_cond_wait" => { - let [cond, mutex] = this.check_shim(abi, Conv::C , link_name, args)?; + let [cond, mutex] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_cond_wait(cond, mutex, dest)?; } "pthread_cond_timedwait" => { - let [cond, mutex, abstime] = this.check_shim(abi, Conv::C , link_name, args)?; + let [cond, mutex, abstime] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let [cond] = this.check_shim(abi, Conv::C , link_name, args)?; + let [cond] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_cond_destroy(cond)?; this.write_null(dest)?; } // Threading "pthread_create" => { - let [thread, attr, start, arg] = this.check_shim(abi, Conv::C , link_name, args)?; + let [thread, attr, start, arg] = this.check_shim(abi, Conv::C, link_name, args)?; this.pthread_create(thread, attr, start, arg)?; this.write_null(dest)?; } "pthread_join" => { - let [thread, retval] = this.check_shim(abi, Conv::C , link_name, args)?; + let [thread, retval] = this.check_shim(abi, Conv::C, link_name, args)?; let res = this.pthread_join(thread, retval)?; this.write_scalar(res, dest)?; } "pthread_detach" => { - let [thread] = this.check_shim(abi, Conv::C , link_name, args)?; + let [thread] = this.check_shim(abi, Conv::C, link_name, args)?; let res = this.pthread_detach(thread)?; this.write_scalar(res, dest)?; } "pthread_self" => { - let [] = this.check_shim(abi, Conv::C , link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; let res = this.pthread_self()?; this.write_scalar(res, dest)?; } "sched_yield" => { - let [] = this.check_shim(abi, Conv::C , link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; this.sched_yield()?; this.write_null(dest)?; } "nanosleep" => { - let [req, rem] = this.check_shim(abi, Conv::C , link_name, args)?; + let [req, rem] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(result, dest)?; } @@ -671,8 +663,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } - let [pid, cpusetsize, mask] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; let mask = this.read_pointer(mask)?; @@ -680,7 +671,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid let thread_id = match pid { 0 => this.active_thread(), - _ => throw_unsup_format!("`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)"), + _ => + throw_unsup_format!( + "`sched_getaffinity` is only supported with a pid of 0 (indicating the current thread)" + ), }; // The mask is stored in chunks, and the size must be a whole number of chunks. @@ -694,7 +688,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } else if let Some(cpuset) = this.machine.thread_cpu_affinity.get(&thread_id) { let cpuset = cpuset.clone(); // we only copy whole chunks of size_of::<c_ulong>() - let byte_count = Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap()); + let byte_count = + Ord::min(cpuset.as_slice().len(), cpusetsize.try_into().unwrap()); this.write_bytes_ptr(mask, cpuset.as_slice()[..byte_count].iter().copied())?; this.write_null(dest)?; } else { @@ -711,8 +706,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } - let [pid, cpusetsize, mask] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [pid, cpusetsize, mask] = this.check_shim(abi, Conv::C, link_name, args)?; let pid = this.read_scalar(pid)?.to_u32()?; let cpusetsize = this.read_target_usize(cpusetsize)?; let mask = this.read_pointer(mask)?; @@ -720,7 +714,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // TODO: when https://github.com/rust-lang/miri/issues/3730 is fixed this should use its notion of tid/pid let thread_id = match pid { 0 => this.active_thread(), - _ => throw_unsup_format!("`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)"), + _ => + throw_unsup_format!( + "`sched_setaffinity` is only supported with a pid of 0 (indicating the current thread)" + ), }; if this.ptr_is_null(mask)? { @@ -729,7 +726,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // NOTE: cpusetsize might be smaller than `CpuAffinityMask::CPU_MASK_BYTES`. // Any unspecified bytes are treated as zero here (none of the CPUs are configured). // This is not exactly documented, so we assume that this is the behavior in practice. - let bits_slice = this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?; + let bits_slice = + this.read_bytes_ptr_strip_provenance(mask, Size::from_bytes(cpusetsize))?; // This ignores the bytes beyond `CpuAffinityMask::CPU_MASK_BYTES` let bits_array: [u8; CpuAffinityMask::CPU_MASK_BYTES] = std::array::from_fn(|i| bits_slice.get(i).copied().unwrap_or(0)); @@ -748,12 +746,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // Miscellaneous "isatty" => { - let [fd] = this.check_shim(abi, Conv::C , link_name, args)?; + let [fd] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.isatty(fd)?; this.write_scalar(result, dest)?; } "pthread_atfork" => { - let [prepare, parent, child] = this.check_shim(abi, Conv::C , link_name, args)?; + let [prepare, parent, child] = this.check_shim(abi, Conv::C, link_name, args)?; this.read_pointer(prepare)?; this.read_pointer(parent)?; this.read_pointer(child)?; @@ -763,15 +761,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "getentropy" => { // This function is non-standard but exists with the same signature and behavior on // Linux, macOS, FreeBSD and Solaris/Illumos. - if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd" | "illumos" | "solaris" | "android") { + if !matches!( + &*this.tcx.sess.target.os, + "linux" | "macos" | "freebsd" | "illumos" | "solaris" | "android" + ) { throw_unsup_format!( "`getentropy` is not supported on {}", this.tcx.sess.target.os ); } - let [buf, bufsize] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [buf, bufsize] = this.check_shim(abi, Conv::C, link_name, args)?; let buf = this.read_pointer(buf)?; let bufsize = this.read_target_usize(bufsize)?; @@ -789,8 +789,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } "strerror_r" => { - let [errnum, buf, buflen] = - this.check_shim(abi, Conv::C, link_name, args)?; + let [errnum, buf, buflen] = this.check_shim(abi, Conv::C, link_name, args)?; let result = this.strerror_r(errnum, buf, buflen)?; this.write_scalar(result, dest)?; } @@ -798,14 +797,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { "getrandom" => { // This function is non-standard but exists with the same signature and behavior on // Linux, FreeBSD and Solaris/Illumos. - if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris" | "android") { + if !matches!( + &*this.tcx.sess.target.os, + "linux" | "freebsd" | "illumos" | "solaris" | "android" + ) { throw_unsup_format!( "`getrandom` is not supported on {}", this.tcx.sess.target.os ); } - let [ptr, len, flags] = - this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr, len, flags] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; let _flags = this.read_scalar(flags)?.to_i32()?; @@ -822,7 +823,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.tcx.sess.target.os ); } - let [ptr, len] = this.check_shim(abi, Conv::C , link_name, args)?; + let [ptr, len] = this.check_shim(abi, Conv::C, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_target_usize(len)?; this.gen_random(ptr, len)?; @@ -841,7 +842,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // For arm32 they did something custom, but similar enough that the same // `_Unwind_RaiseException` impl in miri should work: // https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst - if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos") { + if !matches!( + &*this.tcx.sess.target.os, + "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos" + ) { throw_unsup_format!( "`_Unwind_RaiseException` is not supported on {}", this.tcx.sess.target.os @@ -853,43 +857,42 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return interp_ok(EmulateItemResult::NeedsUnwind); } "getuid" => { - let [] = this.check_shim(abi, Conv::C , link_name, args)?; + let [] = this.check_shim(abi, Conv::C, link_name, args)?; // For now, just pretend we always have this fixed UID. this.write_int(UID, dest)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "pthread_attr_getguardsize" - if this.frame_in_std() => { - let [_attr, guard_size] = this.check_shim(abi, Conv::C , link_name, args)?; + "pthread_attr_getguardsize" if this.frame_in_std() => { + let [_attr, guard_size] = this.check_shim(abi, Conv::C, link_name, args)?; let guard_size = this.deref_pointer(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t"); - this.write_scalar(Scalar::from_uint(this.machine.page_size, guard_size_layout.size), &guard_size)?; + this.write_scalar( + Scalar::from_uint(this.machine.page_size, guard_size_layout.size), + &guard_size, + )?; // Return success (`0`). this.write_null(dest)?; } - | "pthread_attr_init" - | "pthread_attr_destroy" - if this.frame_in_std() => { - let [_] = this.check_shim(abi, Conv::C , link_name, args)?; + "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { + let [_] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_null(dest)?; } - | "pthread_attr_setstacksize" - if this.frame_in_std() => { - let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?; + "pthread_attr_setstacksize" if this.frame_in_std() => { + let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_null(dest)?; } - "pthread_attr_getstack" - if this.frame_in_std() => { + "pthread_attr_getstack" if this.frame_in_std() => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. // Hence we can mostly ignore the input `attr_place`. let [attr_place, addr_place, size_place] = - this.check_shim(abi, Conv::C , link_name, args)?; - let _attr_place = this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?; + this.check_shim(abi, Conv::C, link_name, args)?; + let _attr_place = + this.deref_pointer_as(attr_place, this.libc_ty_layout("pthread_attr_t"))?; let addr_place = this.deref_pointer(addr_place)?; let size_place = this.deref_pointer(size_place)?; @@ -906,24 +909,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_null(dest)?; } - | "signal" - | "sigaltstack" - if this.frame_in_std() => { - let [_, _] = this.check_shim(abi, Conv::C , link_name, args)?; + "signal" | "sigaltstack" if this.frame_in_std() => { + let [_, _] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_null(dest)?; } - | "sigaction" - | "mprotect" - if this.frame_in_std() => { - let [_, _, _] = this.check_shim(abi, Conv::C , link_name, args)?; + "sigaction" | "mprotect" if this.frame_in_std() => { + let [_, _, _] = this.check_shim(abi, Conv::C, link_name, args)?; this.write_null(dest)?; } - "getpwuid_r" | "__posix_getpwuid_r" - if this.frame_in_std() => { + "getpwuid_r" | "__posix_getpwuid_r" if this.frame_in_std() => { // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish let [uid, pwd, buf, buflen, result] = - this.check_shim(abi, Conv::C , link_name, args)?; + this.check_shim(abi, Conv::C, link_name, args)?; this.check_no_isolation("`getpwuid_r`")?; let uid = this.read_scalar(uid)?.to_u32()?; @@ -961,11 +959,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { _ => { let target_os = &*this.tcx.sess.target.os; return match target_os { - "android" => android::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), - "freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), - "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), - "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), - "solaris" | "illumos" => solarish::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest), + "android" => + android::EvalContextExt::emulate_foreign_item_inner( + this, link_name, abi, args, dest, + ), + "freebsd" => + freebsd::EvalContextExt::emulate_foreign_item_inner( + this, link_name, abi, args, dest, + ), + "linux" => + linux::EvalContextExt::emulate_foreign_item_inner( + this, link_name, abi, args, dest, + ), + "macos" => + macos::EvalContextExt::emulate_foreign_item_inner( + this, link_name, abi, args, dest, + ), + "solaris" | "illumos" => + solarish::EvalContextExt::emulate_foreign_item_inner( + this, link_name, abi, args, dest, + ), _ => interp_ok(EmulateItemResult::NotSupported), }; } 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 5381234e28c..03dbd931329 100644 --- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs @@ -21,29 +21,38 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let this = self.eval_context_mut(); match link_name.as_str() { // Threading - "pthread_set_name_np" => { + "pthread_setname_np" => { let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?; let max_len = usize::MAX; // FreeBSD does not seem to have a limit. - // FreeBSD's pthread_set_name_np does not return anything. - this.pthread_setname_np( + let res = match this.pthread_setname_np( this.read_scalar(thread)?, this.read_scalar(name)?, max_len, /* truncate */ false, - )?; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + ThreadNameResult::NameTooLong => unreachable!(), + ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"), + }; + this.write_scalar(res, dest)?; } - "pthread_get_name_np" => { + "pthread_getname_np" => { let [thread, name, len] = this.check_shim(abi, Conv::C, link_name, args)?; - // FreeBSD's pthread_get_name_np does not return anything - // and uses strlcpy, which truncates the resulting value, + // FreeBSD's pthread_getname_np uses strlcpy, which truncates the resulting value, // but always adds a null terminator (except for zero-sized buffers). // https://github.com/freebsd/freebsd-src/blob/c2d93a803acef634bd0eede6673aeea59e90c277/lib/libthr/thread/thr_info.c#L119-L144 - this.pthread_getname_np( + let res = match this.pthread_getname_np( this.read_scalar(thread)?, this.read_scalar(name)?, this.read_scalar(len)?, /* truncate */ true, - )?; + )? { + ThreadNameResult::Ok => Scalar::from_u32(0), + // `NameTooLong` is possible when the buffer is zero sized, + ThreadNameResult::NameTooLong => Scalar::from_u32(0), + ThreadNameResult::ThreadNotFound => this.eval_libc("ESRCH"), + }; + this.write_scalar(res, dest)?; } // File related shims diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs index 5682fb659e7..25594b78031 100644 --- a/src/tools/miri/src/shims/unix/fs.rs +++ b/src/tools/miri/src/shims/unix/fs.rs @@ -31,8 +31,7 @@ impl FileDescription for FileHandle { } fn read<'tcx>( - &self, - _self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, communicate_allowed: bool, ptr: Pointer, len: usize, @@ -49,8 +48,7 @@ impl FileDescription for FileHandle { } fn write<'tcx>( - &self, - _self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, communicate_allowed: bool, ptr: Pointer, len: usize, @@ -76,7 +74,7 @@ impl FileDescription for FileHandle { } fn close<'tcx>( - self: Box<Self>, + self, communicate_allowed: bool, _ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, io::Result<()>> { @@ -87,7 +85,7 @@ impl FileDescription for FileHandle { // to handle possible errors correctly. let result = self.file.sync_all(); // Now we actually close the file and return the result. - drop(*self); + drop(self.file); interp_ok(result) } else { // We drop the file, this closes it but ignores any errors @@ -96,7 +94,7 @@ impl FileDescription for FileHandle { // `/dev/urandom` which are read-only. Check // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 // for a deeper discussion. - drop(*self); + drop(self.file); interp_ok(Ok(())) } } @@ -1311,22 +1309,19 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }; // FIXME: Support ftruncate64 for all FDs - let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| { + let file = fd.downcast::<FileHandle>().ok_or_else(|| { err_unsup_format!("`ftruncate64` is only supported on file-backed file descriptors") })?; - if *writable { + if file.writable { if let Ok(length) = length.try_into() { - let result = file.set_len(length); - drop(fd); + let result = file.file.set_len(length); let result = this.try_unwrap_io_result(result.map(|_| 0i32))?; interp_ok(Scalar::from_i32(result)) } else { - drop(fd); this.set_last_error_and_return_i32(LibcError("EINVAL")) } } else { - drop(fd); // The file is not writable this.set_last_error_and_return_i32(LibcError("EINVAL")) } @@ -1358,11 +1353,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // Only regular files support synchronization. - let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| { + let file = fd.downcast::<FileHandle>().ok_or_else(|| { err_unsup_format!("`fsync` is only supported on file-backed file descriptors") })?; - let io_result = maybe_sync_file(file, *writable, File::sync_all); - drop(fd); + let io_result = maybe_sync_file(&file.file, file.writable, File::sync_all); interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } @@ -1382,11 +1376,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // Only regular files support synchronization. - let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| { + let file = fd.downcast::<FileHandle>().ok_or_else(|| { err_unsup_format!("`fdatasync` is only supported on file-backed file descriptors") })?; - let io_result = maybe_sync_file(file, *writable, File::sync_data); - drop(fd); + let io_result = maybe_sync_file(&file.file, file.writable, File::sync_data); interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } @@ -1425,11 +1418,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { return this.set_last_error_and_return_i32(LibcError("EBADF")); }; // Only regular files support synchronization. - let FileHandle { file, writable } = fd.downcast::<FileHandle>().ok_or_else(|| { + let file = fd.downcast::<FileHandle>().ok_or_else(|| { err_unsup_format!("`sync_data_range` is only supported on file-backed file descriptors") })?; - let io_result = maybe_sync_file(file, *writable, File::sync_data); - drop(fd); + let io_result = maybe_sync_file(&file.file, file.writable, File::sync_data); interp_ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } diff --git a/src/tools/miri/src/shims/unix/linux_like/epoll.rs b/src/tools/miri/src/shims/unix/linux_like/epoll.rs index 5b240351c20..de8bcb54aef 100644 --- a/src/tools/miri/src/shims/unix/linux_like/epoll.rs +++ b/src/tools/miri/src/shims/unix/linux_like/epoll.rs @@ -5,12 +5,14 @@ use std::rc::{Rc, Weak}; use std::time::Duration; use crate::concurrency::VClock; -use crate::shims::files::{FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef}; +use crate::shims::files::{ + DynFileDescriptionRef, FdId, FileDescription, FileDescriptionRef, WeakFileDescriptionRef, +}; use crate::shims::unix::UnixFileDescription; use crate::*; /// An `Epoll` file descriptor connects file handles and epoll events -#[derive(Clone, Debug, Default)] +#[derive(Debug, Default)] struct Epoll { /// A map of EpollEventInterests registered under this epoll instance. /// Each entry is differentiated using FdId and file descriptor value. @@ -18,11 +20,15 @@ struct Epoll { /// A map of EpollEventInstance that will be returned when `epoll_wait` is called. /// Similar to interest_list, the entry is also differentiated using FdId /// and file descriptor value. - // This is an Rc because EpollInterest need to hold a reference to update - // it. - ready_list: Rc<ReadyList>, + ready_list: ReadyList, /// A list of thread ids blocked on this epoll instance. - thread_id: RefCell<Vec<ThreadId>>, + blocked_tid: RefCell<Vec<ThreadId>>, +} + +impl VisitProvenance for Epoll { + fn visit_provenance(&self, _visit: &mut VisitWith<'_>) { + // No provenance anywhere in this type. + } } /// EpollEventInstance contains information that will be returned by epoll_wait. @@ -51,7 +57,7 @@ impl EpollEventInstance { /// see the man page: /// /// <https://man7.org/linux/man-pages/man2/epoll_ctl.2.html> -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct EpollEventInterest { /// The file descriptor value of the file description registered. /// This is only used for ready_list, to inform userspace which FD triggered an event. @@ -65,10 +71,10 @@ pub struct EpollEventInterest { /// but only u64 is supported for now. /// <https://man7.org/linux/man-pages/man3/epoll_event.3type.html> data: u64, - /// Ready list of the epoll instance under which this EpollEventInterest is registered. - ready_list: Rc<ReadyList>, /// The epoll file description that this EpollEventInterest is registered under. - weak_epfd: WeakFileDescriptionRef, + /// This is weak to avoid cycles, but an upgrade is always guaranteed to succeed + /// because only the `Epoll` holds a strong ref to a `EpollEventInterest`. + weak_epfd: WeakFileDescriptionRef<Epoll>, } /// EpollReadyEvents reflects the readiness of a file description. @@ -134,19 +140,13 @@ impl EpollReadyEvents { } } -impl Epoll { - fn get_ready_list(&self) -> Rc<ReadyList> { - Rc::clone(&self.ready_list) - } -} - impl FileDescription for Epoll { fn name(&self) -> &'static str { "epoll" } fn close<'tcx>( - self: Box<Self>, + self, _communicate_allowed: bool, _ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, io::Result<()>> { @@ -271,17 +271,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Some(epfd) = this.machine.fds.get(epfd_value) else { return this.set_last_error_and_return_i32(LibcError("EBADF")); }; - let epoll_file_description = epfd + let epfd = epfd .downcast::<Epoll>() .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_ctl`"))?; - let mut interest_list = epoll_file_description.interest_list.borrow_mut(); - let ready_list = &epoll_file_description.ready_list; + let mut interest_list = epfd.interest_list.borrow_mut(); let Some(fd_ref) = this.machine.fds.get(fd) else { return this.set_last_error_and_return_i32(LibcError("EBADF")); }; - let id = fd_ref.get_id(); + let id = fd_ref.id(); if op == epoll_ctl_add || op == epoll_ctl_mod { // Read event bitmask and data from epoll_event passed by caller. @@ -337,30 +336,33 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { } } - // Create an epoll_interest. - let interest = Rc::new(RefCell::new(EpollEventInterest { - fd_num: fd, - events, - data, - ready_list: Rc::clone(ready_list), - weak_epfd: epfd.downgrade(), - })); - if op == epoll_ctl_add { + // Create an epoll_interest. + let interest = Rc::new(RefCell::new(EpollEventInterest { + fd_num: fd, + events, + data, + weak_epfd: FileDescriptionRef::downgrade(&epfd), + })); + // Notification will be returned for current epfd if there is event in the file + // descriptor we registered. + check_and_update_one_event_interest(&fd_ref, &interest, id, this)?; + // Insert an epoll_interest to global epoll_interest list. this.machine.epoll_interests.insert_epoll_interest(id, Rc::downgrade(&interest)); - interest_list.insert(epoll_key, Rc::clone(&interest)); + interest_list.insert(epoll_key, interest); } else { - // Directly modify the epoll_interest so the global epoll_event_interest table - // will be updated too. - let mut epoll_interest = interest_list.get_mut(&epoll_key).unwrap().borrow_mut(); - epoll_interest.events = events; - epoll_interest.data = data; + // Modify the existing interest. + let epoll_interest = interest_list.get_mut(&epoll_key).unwrap(); + { + let mut epoll_interest = epoll_interest.borrow_mut(); + epoll_interest.events = events; + epoll_interest.data = data; + } + // Updating an FD interest triggers events. + check_and_update_one_event_interest(&fd_ref, epoll_interest, id, this)?; } - // Notification will be returned for current epfd if there is event in the file - // descriptor we registered. - check_and_update_one_event_interest(&fd_ref, interest, id, this)?; interp_ok(Scalar::from_i32(0)) } else if op == epoll_ctl_del { let epoll_key = (id, fd); @@ -373,7 +375,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { drop(epoll_interest); // Remove related epoll_interest from ready list. - ready_list.mapping.borrow_mut().remove(&epoll_key); + epfd.ready_list.mapping.borrow_mut().remove(&epoll_key); // Remove dangling EpollEventInterest from its global table. // .unwrap() below should succeed because the file description id must have registered @@ -452,24 +454,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let Some(epfd) = this.machine.fds.get(epfd_value) else { return this.set_last_error_and_return(LibcError("EBADF"), dest); }; - // Create a weak ref of epfd and pass it to callback so we will make sure that epfd - // is not close after the thread unblocks. - let weak_epfd = epfd.downgrade(); + let Some(epfd) = epfd.downcast::<Epoll>() else { + return this.set_last_error_and_return(LibcError("EBADF"), dest); + }; // We just need to know if the ready list is empty and borrow the thread_ids out. - // The whole logic is wrapped inside a block so we don't need to manually drop epfd later. - let ready_list_empty; - let mut thread_ids; - { - let epoll_file_description = epfd - .downcast::<Epoll>() - .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; - ready_list_empty = epoll_file_description.ready_list.mapping.borrow().is_empty(); - thread_ids = epoll_file_description.thread_id.borrow_mut(); - } + let ready_list_empty = epfd.ready_list.mapping.borrow().is_empty(); if timeout == 0 || !ready_list_empty { // If the ready list is not empty, or the timeout is 0, we can return immediately. - return_ready_list(epfd_value, weak_epfd, dest, &event, this)?; + return_ready_list(&epfd, dest, &event, this)?; } else { // Blocking let timeout = match timeout { @@ -484,34 +477,37 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } }; - thread_ids.push(this.active_thread()); + // Record this thread as blocked. + epfd.blocked_tid.borrow_mut().push(this.active_thread()); + // And block it. let dest = dest.clone(); + // We keep a strong ref to the underlying `Epoll` to make sure it sticks around. + // This means there'll be a leak if we never wake up, but that anyway would imply + // a thread is permanently blocked so this is fine. this.block_thread( BlockReason::Epoll, timeout, callback!( @capture<'tcx> { - epfd_value: i32, - weak_epfd: WeakFileDescriptionRef, + epfd: FileDescriptionRef<Epoll>, dest: MPlaceTy<'tcx>, event: MPlaceTy<'tcx>, } - @unblock = |this| { - return_ready_list(epfd_value, weak_epfd, &dest, &event, this)?; - interp_ok(()) - } - @timeout = |this| { - // No notification after blocking timeout. - let Some(epfd) = weak_epfd.upgrade() else { - throw_unsup_format!("epoll FD {epfd_value} got closed while blocking.") - }; - // Remove the current active thread_id from the blocked thread_id list. - epfd.downcast::<Epoll>() - .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))? - .thread_id.borrow_mut() - .retain(|&id| id != this.active_thread()); - this.write_int(0, &dest)?; - interp_ok(()) + |this, unblock: UnblockKind| { + match unblock { + UnblockKind::Ready => { + return_ready_list(&epfd, &dest, &event, this)?; + interp_ok(()) + }, + UnblockKind::TimedOut => { + // Remove the current active thread_id from the blocked thread_id list. + epfd + .blocked_tid.borrow_mut() + .retain(|&id| id != this.active_thread()); + this.write_int(0, &dest)?; + interp_ok(()) + }, + } } ), ); @@ -528,21 +524,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// do not call this function when an FD didn't have anything happen to it! fn check_and_update_readiness( &mut self, - fd_ref: &FileDescriptionRef, + fd_ref: DynFileDescriptionRef, ) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); - let id = fd_ref.get_id(); + let id = fd_ref.id(); let mut waiter = Vec::new(); // Get a list of EpollEventInterest that is associated to a specific file description. if let Some(epoll_interests) = this.machine.epoll_interests.get_epoll_interest(id) { for weak_epoll_interest in epoll_interests { if let Some(epoll_interest) = weak_epoll_interest.upgrade() { - let is_updated = check_and_update_one_event_interest( - fd_ref, - epoll_interest.clone(), - id, - this, - )?; + let is_updated = + check_and_update_one_event_interest(&fd_ref, &epoll_interest, id, this)?; if is_updated { // Edge-triggered notification only notify one thread even if there are // multiple threads blocked on the same epfd. @@ -553,10 +545,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { // holds a strong ref to epoll_interest. let epfd = epoll_interest.borrow().weak_epfd.upgrade().unwrap(); // FIXME: We can randomly pick a thread to unblock. - - let epoll = epfd.downcast::<Epoll>().unwrap(); - - if let Some(thread_id) = epoll.thread_id.borrow_mut().pop() { + if let Some(thread_id) = epfd.blocked_tid.borrow_mut().pop() { waiter.push(thread_id); }; } @@ -595,14 +584,15 @@ fn ready_list_next( /// notification was added/updated. Unlike check_and_update_readiness, this function sends a /// notification to only one epoll instance. fn check_and_update_one_event_interest<'tcx>( - fd_ref: &FileDescriptionRef, - interest: Rc<RefCell<EpollEventInterest>>, + fd_ref: &DynFileDescriptionRef, + interest: &RefCell<EpollEventInterest>, id: FdId, ecx: &MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, bool> { // Get the bitmask of ready events for a file description. let ready_events_bitmask = fd_ref.as_unix().get_epoll_ready_events()?.get_event_bitmask(ecx); let epoll_event_interest = interest.borrow(); + let epfd = epoll_event_interest.weak_epfd.upgrade().unwrap(); // This checks if any of the events specified in epoll_event_interest.events // match those in ready_events. let flags = epoll_event_interest.events & ready_events_bitmask; @@ -610,7 +600,7 @@ fn check_and_update_one_event_interest<'tcx>( // insert an epoll_return to the ready list. if flags != 0 { let epoll_key = (id, epoll_event_interest.fd_num); - let ready_list = &mut epoll_event_interest.ready_list.mapping.borrow_mut(); + let mut ready_list = epfd.ready_list.mapping.borrow_mut(); let mut event_instance = EpollEventInstance::new(flags, epoll_event_interest.data); // If we are tracking data races, remember the current clock so we can sync with it later. ecx.release_clock(|clock| { @@ -627,23 +617,12 @@ fn check_and_update_one_event_interest<'tcx>( /// Stores the ready list of the `epfd` epoll instance into `events` (which must be an array), /// and the number of returned events into `dest`. fn return_ready_list<'tcx>( - epfd_value: i32, - weak_epfd: WeakFileDescriptionRef, + epfd: &FileDescriptionRef<Epoll>, dest: &MPlaceTy<'tcx>, events: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { - let Some(epfd) = weak_epfd.upgrade() else { - throw_unsup_format!("epoll FD {epfd_value} got closed while blocking.") - }; - - let epoll_file_description = epfd - .downcast::<Epoll>() - .ok_or_else(|| err_unsup_format!("non-epoll FD passed to `epoll_wait`"))?; - - let ready_list = epoll_file_description.get_ready_list(); - - let mut ready_list = ready_list.mapping.borrow_mut(); + let mut ready_list = epfd.ready_list.mapping.borrow_mut(); let mut num_of_events: i32 = 0; let mut array_iter = ecx.project_array_fields(events)?; diff --git a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs index 4bbe417ea8d..4b76bbb2b4d 100644 --- a/src/tools/miri/src/shims/unix/linux_like/eventfd.rs +++ b/src/tools/miri/src/shims/unix/linux_like/eventfd.rs @@ -20,7 +20,7 @@ const MAX_COUNTER: u64 = u64::MAX - 1; /// /// <https://man.netbsd.org/eventfd.2> #[derive(Debug)] -struct Event { +struct EventFd { /// 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. counter: Cell<u64>, @@ -32,13 +32,13 @@ struct Event { blocked_write_tid: RefCell<Vec<ThreadId>>, } -impl FileDescription for Event { +impl FileDescription for EventFd { fn name(&self) -> &'static str { "event" } fn close<'tcx>( - self: Box<Self>, + self, _communicate_allowed: bool, _ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, io::Result<()>> { @@ -47,8 +47,7 @@ impl FileDescription for Event { /// Read the counter in the buffer and return the counter if succeeded. fn read<'tcx>( - &self, - self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, _communicate_allowed: bool, ptr: Pointer, len: usize, @@ -62,11 +61,10 @@ impl FileDescription for Event { return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); } - // eventfd read at the size of u64. + // Turn the pointer into a place at the right type. let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty); - let weak_eventfd = self_ref.downgrade(); - eventfd_read(buf_place, dest, weak_eventfd, ecx) + eventfd_read(buf_place, dest, self, ecx) } /// A write call adds the 8-byte integer value supplied in @@ -82,8 +80,7 @@ impl FileDescription for Event { /// supplied buffer is less than 8 bytes, or if an attempt is /// made to write the value 0xffffffffffffffff. fn write<'tcx>( - &self, - self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, _communicate_allowed: bool, ptr: Pointer, len: usize, @@ -97,18 +94,10 @@ impl FileDescription for Event { return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); } - // Read the user-supplied value from the pointer. + // Turn the pointer into a place at the right type. let buf_place = ecx.ptr_to_mplace_unaligned(ptr, ty); - let num = ecx.read_scalar(&buf_place)?.to_u64()?; - // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1. - if num == u64::MAX { - return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); - } - // If the addition does not let the counter to exceed the maximum value, update the counter. - // Else, block. - let weak_eventfd = self_ref.downgrade(); - eventfd_write(num, buf_place, dest, weak_eventfd, ecx) + eventfd_write(buf_place, dest, self, ecx) } fn as_unix(&self) -> &dyn UnixFileDescription { @@ -116,7 +105,7 @@ impl FileDescription for Event { } } -impl UnixFileDescription for Event { +impl UnixFileDescription for EventFd { fn get_epoll_ready_events<'tcx>(&self) -> InterpResult<'tcx, EpollReadyEvents> { // We only check the status of EPOLLIN and EPOLLOUT flags for eventfd. If other event flags // need to be supported in the future, the check should be added here. @@ -178,7 +167,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let fds = &mut this.machine.fds; - let fd_value = fds.insert_new(Event { + let fd_value = fds.insert_new(EventFd { counter: Cell::new(val.into()), is_nonblock, clock: RefCell::new(VClock::default()), @@ -193,19 +182,17 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { /// Block thread if the value addition will exceed u64::MAX -1, /// else just add the user-supplied value to current counter. fn eventfd_write<'tcx>( - num: u64, buf_place: MPlaceTy<'tcx>, dest: &MPlaceTy<'tcx>, - weak_eventfd: WeakFileDescriptionRef, + eventfd: FileDescriptionRef<EventFd>, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { - let Some(eventfd_ref) = weak_eventfd.upgrade() else { - throw_unsup_format!("eventfd FD got closed while blocking.") - }; - - // Since we pass the weak file description ref, it is guaranteed to be - // an eventfd file description. - let eventfd = eventfd_ref.downcast::<Event>().unwrap(); + // Figure out which value we should add. + let num = ecx.read_scalar(&buf_place)?.to_u64()?; + // u64::MAX as input is invalid because the maximum value of counter is u64::MAX - 1. + if num == u64::MAX { + return ecx.set_last_error_and_return(ErrorKind::InvalidInput, dest); + } match eventfd.counter.get().checked_add(num) { Some(new_count @ 0..=MAX_COUNTER) => { @@ -217,10 +204,6 @@ fn eventfd_write<'tcx>( // Store new counter value. eventfd.counter.set(new_count); - // The state changed; we check and update the status of all supported event - // types for current file description. - ecx.check_and_update_readiness(&eventfd_ref)?; - // Unblock *all* threads previously blocked on `read`. // We need to take out the blocked thread ids and unblock them together, // because `unblock_threads` may block them again and end up re-adding the @@ -231,6 +214,10 @@ fn eventfd_write<'tcx>( ecx.unblock_thread(thread_id, BlockReason::Eventfd)?; } + // The state changed; we check and update the status of all supported event + // types for current file description. + ecx.check_and_update_readiness(eventfd)?; + // Return how many bytes we consumed from the user-provided buffer. return ecx.write_int(buf_place.layout.size.bytes(), dest); } @@ -244,6 +231,7 @@ fn eventfd_write<'tcx>( eventfd.blocked_write_tid.borrow_mut().push(ecx.active_thread()); + let weak_eventfd = FileDescriptionRef::downgrade(&eventfd); ecx.block_thread( BlockReason::Eventfd, None, @@ -252,11 +240,14 @@ fn eventfd_write<'tcx>( num: u64, buf_place: MPlaceTy<'tcx>, dest: MPlaceTy<'tcx>, - weak_eventfd: WeakFileDescriptionRef, + weak_eventfd: WeakFileDescriptionRef<EventFd>, } - @unblock = |this| { - // When we get unblocked, try again. - eventfd_write(num, buf_place, &dest, weak_eventfd, this) + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); + // When we get unblocked, try again. We know the ref is still valid, + // otherwise there couldn't be a `write` that unblocks us. + let eventfd_ref = weak_eventfd.upgrade().unwrap(); + eventfd_write(buf_place, &dest, eventfd_ref, this) } ), ); @@ -270,17 +261,9 @@ fn eventfd_write<'tcx>( fn eventfd_read<'tcx>( buf_place: MPlaceTy<'tcx>, dest: &MPlaceTy<'tcx>, - weak_eventfd: WeakFileDescriptionRef, + eventfd: FileDescriptionRef<EventFd>, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { - let Some(eventfd_ref) = weak_eventfd.upgrade() else { - throw_unsup_format!("eventfd FD got closed while blocking.") - }; - - // Since we pass the weak file description ref to the callback function, it is guaranteed to be - // an eventfd file description. - let eventfd = eventfd_ref.downcast::<Event>().unwrap(); - // Set counter to 0, get old value. let counter = eventfd.counter.replace(0); @@ -293,6 +276,7 @@ fn eventfd_read<'tcx>( eventfd.blocked_read_tid.borrow_mut().push(ecx.active_thread()); + let weak_eventfd = FileDescriptionRef::downgrade(&eventfd); ecx.block_thread( BlockReason::Eventfd, None, @@ -300,11 +284,14 @@ fn eventfd_read<'tcx>( @capture<'tcx> { buf_place: MPlaceTy<'tcx>, dest: MPlaceTy<'tcx>, - weak_eventfd: WeakFileDescriptionRef, + weak_eventfd: WeakFileDescriptionRef<EventFd>, } - @unblock = |this| { - // When we get unblocked, try again. - eventfd_read(buf_place, &dest, weak_eventfd, this) + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); + // When we get unblocked, try again. We know the ref is still valid, + // otherwise there couldn't be a `write` that unblocks us. + let eventfd_ref = weak_eventfd.upgrade().unwrap(); + eventfd_read(buf_place, &dest, eventfd_ref, this) } ), ); @@ -315,10 +302,6 @@ fn eventfd_read<'tcx>( // Return old counter value into user-space buffer. ecx.write_int(counter, &buf_place)?; - // The state changed; we check and update the status of all supported event - // types for current file description. - ecx.check_and_update_readiness(&eventfd_ref)?; - // Unblock *all* threads previously blocked on `write`. // We need to take out the blocked thread ids and unblock them together, // because `unblock_threads` may block them again and end up re-adding the @@ -329,6 +312,10 @@ fn eventfd_read<'tcx>( ecx.unblock_thread(thread_id, BlockReason::Eventfd)?; } + // The state changed; we check and update the status of all supported event + // types for current file description. + ecx.check_and_update_readiness(eventfd)?; + // Tell userspace how many bytes we put into the buffer. return ecx.write_int(buf_place.layout.size.bytes(), dest); } 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 aa291639a6d..85c963774a1 100644 --- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; use super::sync::EvalContextExt as _; +use crate::helpers::check_min_arg_count; use crate::shims::unix::*; use crate::*; @@ -67,6 +68,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { let result = this.realpath(path, resolved_path)?; this.write_scalar(result, dest)?; } + "ioctl" => { + // `ioctl` is variadic. The argument count is checked based on the first argument + // in `this.ioctl()`, so we do not use `check_shim` here. + this.check_abi_and_shim_symbol_clash(abi, Conv::C, link_name)?; + let result = this.ioctl(args)?; + this.write_scalar(result, dest)?; + } // Environment related shims "_NSGetEnviron" => { @@ -112,7 +120,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.check_no_isolation("`_NSGetExecutablePath`")?; let buf_ptr = this.read_pointer(buf)?; - let bufsize = this.deref_pointer(bufsize)?; + let bufsize = this.deref_pointer_as(bufsize, this.machine.layouts.u32)?; // Using the host current_exe is a bit off, but consistent with Linux // (where stdlib reads /proc/self/exe). @@ -234,4 +242,26 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { interp_ok(EmulateItemResult::NeedsReturn) } + + fn ioctl(&mut self, args: &[OpTy<'tcx>]) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let fioclex = this.eval_libc_u64("FIOCLEX"); + + let [fd_num, cmd] = check_min_arg_count("ioctl", args)?; + let fd_num = this.read_scalar(fd_num)?.to_i32()?; + let cmd = this.read_scalar(cmd)?.to_u64()?; + + if cmd == fioclex { + // Since we don't support `exec`, this is a NOP. However, we want to + // return EBADF if the FD is invalid. + if this.machine.fds.is_fd_num(fd_num) { + interp_ok(Scalar::from_i32(0)) + } else { + this.set_last_error_and_return_i32(LibcError("EBADF")) + } + } else { + throw_unsup_format!("ioctl: unsupported command {cmd:#x}"); + } + } } diff --git a/src/tools/miri/src/shims/unix/macos/sync.rs b/src/tools/miri/src/shims/unix/macos/sync.rs index f66a57ae706..330c64f06a3 100644 --- a/src/tools/miri/src/shims/unix/macos/sync.rs +++ b/src/tools/miri/src/shims/unix/macos/sync.rs @@ -64,7 +64,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { None, callback!( @capture<'tcx> {} - @unblock = |_this| { + |_this, _unblock: UnblockKind| { panic!("we shouldn't wake up ever") } ), 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 c99e8ae7c6e..f94783a3907 100644 --- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs +++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs @@ -3,6 +3,8 @@ use rustc_span::Symbol; use rustc_target::callconv::{Conv, FnAbi}; use crate::shims::unix::foreign_items::EvalContextExt as _; +use crate::shims::unix::linux_like::epoll::EvalContextExt as _; +use crate::shims::unix::linux_like::eventfd::EvalContextExt as _; use crate::shims::unix::*; use crate::*; @@ -21,6 +23,32 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ) -> InterpResult<'tcx, EmulateItemResult> { let this = self.eval_context_mut(); match link_name.as_str() { + // epoll, eventfd (NOT available on Solaris!) + "epoll_create1" => { + this.assert_target_os("illumos", "epoll_create1"); + let [flag] = this.check_shim(abi, Conv::C, link_name, args)?; + let result = this.epoll_create1(flag)?; + this.write_scalar(result, dest)?; + } + "epoll_ctl" => { + this.assert_target_os("illumos", "epoll_ctl"); + let [epfd, op, fd, event] = this.check_shim(abi, Conv::C, link_name, args)?; + let result = this.epoll_ctl(epfd, op, fd, event)?; + this.write_scalar(result, dest)?; + } + "epoll_wait" => { + this.assert_target_os("illumos", "epoll_wait"); + let [epfd, events, maxevents, timeout] = + this.check_shim(abi, Conv::C, link_name, args)?; + this.epoll_wait(epfd, events, maxevents, timeout, dest)?; + } + "eventfd" => { + this.assert_target_os("illumos", "eventfd"); + let [val, flag] = this.check_shim(abi, Conv::C, link_name, args)?; + let result = this.eventfd(val, flag)?; + this.write_scalar(result, dest)?; + } + // Threading "pthread_setname_np" => { let [thread, name] = this.check_shim(abi, Conv::C, link_name, args)?; @@ -78,6 +106,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { this.write_scalar(result, dest)?; } + // Sockets and pipes + "__xnet_socketpair" => { + let [domain, type_, protocol, sv] = + this.check_shim(abi, Conv::C, link_name, args)?; + let result = this.socketpair(domain, type_, protocol, sv)?; + this.write_scalar(result, dest)?; + } + // Miscellaneous "___errno" => { let [] = this.check_shim(abi, Conv::C, link_name, args)?; diff --git a/src/tools/miri/src/shims/unix/unnamed_socket.rs b/src/tools/miri/src/shims/unix/unnamed_socket.rs index 86ebe95762a..08515b815a9 100644 --- a/src/tools/miri/src/shims/unix/unnamed_socket.rs +++ b/src/tools/miri/src/shims/unix/unnamed_socket.rs @@ -31,7 +31,7 @@ struct AnonSocket { /// The `AnonSocket` file descriptor that is our "peer", and that holds the buffer we are /// writing to. This is a weak reference because the other side may be closed before us; all /// future writes will then trigger EPIPE. - peer_fd: OnceCell<WeakFileDescriptionRef>, + peer_fd: OnceCell<WeakFileDescriptionRef<AnonSocket>>, /// Indicates whether the peer has lost data when the file description is closed. /// This flag is set to `true` if the peer's `readbuf` is non-empty at the time /// of closure. @@ -58,7 +58,7 @@ impl Buffer { } impl AnonSocket { - fn peer_fd(&self) -> &WeakFileDescriptionRef { + fn peer_fd(&self) -> &WeakFileDescriptionRef<AnonSocket> { self.peer_fd.get().unwrap() } } @@ -69,7 +69,7 @@ impl FileDescription for AnonSocket { } fn close<'tcx>( - self: Box<Self>, + self, _communicate_allowed: bool, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx, io::Result<()>> { @@ -78,80 +78,35 @@ impl FileDescription for AnonSocket { // notify the peer that data lost has happened in current file description. if let Some(readbuf) = &self.readbuf { if !readbuf.borrow().buf.is_empty() { - peer_fd.downcast::<AnonSocket>().unwrap().peer_lost_data.set(true); + peer_fd.peer_lost_data.set(true); } } // Notify peer fd that close has happened, since that can unblock reads and writes. - ecx.check_and_update_readiness(&peer_fd)?; + ecx.check_and_update_readiness(peer_fd)?; } interp_ok(Ok(())) } fn read<'tcx>( - &self, - self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, _communicate_allowed: bool, ptr: Pointer, len: usize, dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { - // Always succeed on read size 0. - if len == 0 { - return ecx.return_read_success(ptr, &[], 0, dest); - } - - let Some(readbuf) = &self.readbuf else { - // FIXME: This should return EBADF, but there's no nice way to do that as there's no - // corresponding ErrorKind variant. - throw_unsup_format!("reading from the write end of a pipe"); - }; - - if readbuf.borrow().buf.is_empty() && self.is_nonblock { - // Non-blocking socketpair with writer and empty buffer. - // https://linux.die.net/man/2/read - // EAGAIN or EWOULDBLOCK can be returned for socket, - // POSIX.1-2001 allows either error to be returned for this case. - // Since there is no ErrorKind for EAGAIN, WouldBlock is used. - return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); - } - anonsocket_read(self_ref.downgrade(), len, ptr, dest.clone(), ecx) + anonsocket_read(self, len, ptr, dest, ecx) } fn write<'tcx>( - &self, - self_ref: &FileDescriptionRef, + self: FileDescriptionRef<Self>, _communicate_allowed: bool, ptr: Pointer, len: usize, dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { - // Always succeed on write size 0. - // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.") - if len == 0 { - return ecx.return_write_success(0, dest); - } - - // We are writing to our peer's readbuf. - let Some(peer_fd) = self.peer_fd().upgrade() else { - // If the upgrade from Weak to Rc fails, it indicates that all read ends have been - // closed. - return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest); - }; - - let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf else { - // FIXME: This should return EBADF, but there's no nice way to do that as there's no - // corresponding ErrorKind variant. - throw_unsup_format!("writing to the reading end of a pipe"); - }; - let available_space = - MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(writebuf.borrow().buf.len()); - if available_space == 0 && self.is_nonblock { - // Non-blocking socketpair with a full buffer. - return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); - } - anonsocket_write(self_ref.downgrade(), ptr, len, dest.clone(), ecx) + anonsocket_write(self, ptr, len, dest, ecx) } fn as_unix(&self) -> &dyn UnixFileDescription { @@ -161,50 +116,64 @@ impl FileDescription for AnonSocket { /// Write to AnonSocket based on the space available and return the written byte size. fn anonsocket_write<'tcx>( - weak_self_ref: WeakFileDescriptionRef, + self_ref: FileDescriptionRef<AnonSocket>, ptr: Pointer, len: usize, - dest: MPlaceTy<'tcx>, + dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { - let Some(self_ref) = weak_self_ref.upgrade() else { - // FIXME: We should raise a deadlock error if the self_ref upgrade failed. - throw_unsup_format!("This will be a deadlock error in future") - }; - let self_anonsocket = self_ref.downcast::<AnonSocket>().unwrap(); - let Some(peer_fd) = self_anonsocket.peer_fd().upgrade() else { + // Always succeed on write size 0. + // ("If count is zero and fd refers to a file other than a regular file, the results are not specified.") + if len == 0 { + return ecx.return_write_success(0, dest); + } + + // We are writing to our peer's readbuf. + let Some(peer_fd) = self_ref.peer_fd().upgrade() else { // If the upgrade from Weak to Rc fails, it indicates that all read ends have been - // closed. - return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, &dest); + // closed. It is an error to write even if there would be space. + return ecx.set_last_error_and_return(ErrorKind::BrokenPipe, dest); }; - let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf else { - // FIXME: This should return EBADF, but there's no nice way to do that as there's no - // corresponding ErrorKind variant. - throw_unsup_format!("writing to the reading end of a pipe") + + let Some(writebuf) = &peer_fd.readbuf else { + // Writing to the read end of a pipe. + return ecx.set_last_error_and_return(IoError::LibcError("EBADF"), dest); }; + // Let's see if we can write. let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(writebuf.borrow().buf.len()); - if available_space == 0 { - // Blocking socketpair with a full buffer. - let dest = dest.clone(); - self_anonsocket.blocked_write_tid.borrow_mut().push(ecx.active_thread()); - ecx.block_thread( - BlockReason::UnnamedSocket, - None, - callback!( - @capture<'tcx> { - weak_self_ref: WeakFileDescriptionRef, - ptr: Pointer, - len: usize, - dest: MPlaceTy<'tcx>, - } - @unblock = |this| { - anonsocket_write(weak_self_ref, ptr, len, dest, this) - } - ), - ); + if self_ref.is_nonblock { + // Non-blocking socketpair with a full buffer. + return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); + } else { + self_ref.blocked_write_tid.borrow_mut().push(ecx.active_thread()); + // Blocking socketpair with a full buffer. + // Block the current thread; only keep a weak ref for this. + let weak_self_ref = FileDescriptionRef::downgrade(&self_ref); + let dest = dest.clone(); + ecx.block_thread( + BlockReason::UnnamedSocket, + None, + callback!( + @capture<'tcx> { + weak_self_ref: WeakFileDescriptionRef<AnonSocket>, + ptr: Pointer, + len: usize, + dest: MPlaceTy<'tcx>, + } + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); + // If we got unblocked, then our peer successfully upgraded its weak + // ref to us. That means we can also upgrade our weak ref. + let self_ref = weak_self_ref.upgrade().unwrap(); + anonsocket_write(self_ref, ptr, len, &dest, this) + } + ), + ); + } } else { + // There is space to write! let mut writebuf = writebuf.borrow_mut(); // Remember this clock so `read` can synchronize with us. ecx.release_clock(|clock| { @@ -218,68 +187,80 @@ fn anonsocket_write<'tcx>( // Need to stop accessing peer_fd so that it can be notified. drop(writebuf); - // Notification should be provided for peer fd as it became readable. - // The kernel does this even if the fd was already readable before, so we follow suit. - ecx.check_and_update_readiness(&peer_fd)?; - let peer_anonsocket = peer_fd.downcast::<AnonSocket>().unwrap(); // Unblock all threads that are currently blocked on peer_fd's read. - let waiting_threads = std::mem::take(&mut *peer_anonsocket.blocked_read_tid.borrow_mut()); + let waiting_threads = std::mem::take(&mut *peer_fd.blocked_read_tid.borrow_mut()); // FIXME: We can randomize the order of unblocking. for thread_id in waiting_threads { ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?; } + // Notification should be provided for peer fd as it became readable. + // The kernel does this even if the fd was already readable before, so we follow suit. + ecx.check_and_update_readiness(peer_fd)?; - return ecx.return_write_success(actual_write_size, &dest); + return ecx.return_write_success(actual_write_size, dest); } interp_ok(()) } /// Read from AnonSocket and return the number of bytes read. fn anonsocket_read<'tcx>( - weak_self_ref: WeakFileDescriptionRef, + self_ref: FileDescriptionRef<AnonSocket>, len: usize, ptr: Pointer, - dest: MPlaceTy<'tcx>, + dest: &MPlaceTy<'tcx>, ecx: &mut MiriInterpCx<'tcx>, ) -> InterpResult<'tcx> { - let Some(self_ref) = weak_self_ref.upgrade() else { - // FIXME: We should raise a deadlock error if the self_ref upgrade failed. - throw_unsup_format!("This will be a deadlock error in future") - }; - let self_anonsocket = self_ref.downcast::<AnonSocket>().unwrap(); + // Always succeed on read size 0. + if len == 0 { + return ecx.return_read_success(ptr, &[], 0, dest); + } - let Some(readbuf) = &self_anonsocket.readbuf else { + let Some(readbuf) = &self_ref.readbuf else { // FIXME: This should return EBADF, but there's no nice way to do that as there's no // corresponding ErrorKind variant. throw_unsup_format!("reading from the write end of a pipe") }; if readbuf.borrow_mut().buf.is_empty() { - if self_anonsocket.peer_fd().upgrade().is_none() { + if self_ref.peer_fd().upgrade().is_none() { // Socketpair with no peer and empty buffer. // 0 bytes successfully read indicates end-of-file. - return ecx.return_read_success(ptr, &[], 0, &dest); + return ecx.return_read_success(ptr, &[], 0, dest); + } else if self_ref.is_nonblock { + // Non-blocking socketpair with writer and empty buffer. + // https://linux.die.net/man/2/read + // EAGAIN or EWOULDBLOCK can be returned for socket, + // POSIX.1-2001 allows either error to be returned for this case. + // Since there is no ErrorKind for EAGAIN, WouldBlock is used. + return ecx.set_last_error_and_return(ErrorKind::WouldBlock, dest); } else { + self_ref.blocked_read_tid.borrow_mut().push(ecx.active_thread()); // Blocking socketpair with writer and empty buffer. - let weak_self_ref = weak_self_ref.clone(); - self_anonsocket.blocked_read_tid.borrow_mut().push(ecx.active_thread()); + // Block the current thread; only keep a weak ref for this. + let weak_self_ref = FileDescriptionRef::downgrade(&self_ref); + let dest = dest.clone(); ecx.block_thread( BlockReason::UnnamedSocket, None, callback!( @capture<'tcx> { - weak_self_ref: WeakFileDescriptionRef, + weak_self_ref: WeakFileDescriptionRef<AnonSocket>, len: usize, ptr: Pointer, dest: MPlaceTy<'tcx>, } - @unblock = |this| { - anonsocket_read(weak_self_ref, len, ptr, dest, this) + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); + // If we got unblocked, then our peer successfully upgraded its weak + // ref to us. That means we can also upgrade our weak ref. + let self_ref = weak_self_ref.upgrade().unwrap(); + anonsocket_read(self_ref, len, ptr, &dest, this) } ), ); } } else { + // There's data to be read! let mut bytes = vec![0; len]; let mut readbuf = readbuf.borrow_mut(); // Synchronize with all previous writes to this buffer. @@ -301,19 +282,18 @@ fn anonsocket_read<'tcx>( // don't know what that *certain number* is, we will provide a notification every time // a read is successful. This might result in our epoll emulation providing more // notifications than the real system. - if let Some(peer_fd) = self_anonsocket.peer_fd().upgrade() { - ecx.check_and_update_readiness(&peer_fd)?; - let peer_anonsocket = peer_fd.downcast::<AnonSocket>().unwrap(); + if let Some(peer_fd) = self_ref.peer_fd().upgrade() { // Unblock all threads that are currently blocked on peer_fd's write. - let waiting_threads = - std::mem::take(&mut *peer_anonsocket.blocked_write_tid.borrow_mut()); + let waiting_threads = std::mem::take(&mut *peer_fd.blocked_write_tid.borrow_mut()); // FIXME: We can randomize the order of unblocking. for thread_id in waiting_threads { ecx.unblock_thread(thread_id, BlockReason::UnnamedSocket)?; } + // Notify epoll waiters. + ecx.check_and_update_readiness(peer_fd)?; }; - return ecx.return_read_success(ptr, &bytes, actual_read_size, &dest); + return ecx.return_read_success(ptr, &bytes, actual_read_size, dest); } interp_ok(()) } @@ -337,7 +317,7 @@ impl UnixFileDescription for AnonSocket { // Check if is writable. if let Some(peer_fd) = self.peer_fd().upgrade() { - if let Some(writebuf) = &peer_fd.downcast::<AnonSocket>().unwrap().readbuf { + if let Some(writebuf) = &peer_fd.readbuf { let data_size = writebuf.borrow().buf.len(); let available_space = MAX_SOCKETPAIR_BUFFER_CAPACITY.strict_sub(data_size); if available_space != 0 { @@ -443,8 +423,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }); // Make the file descriptions point to each other. - fd0.downcast::<AnonSocket>().unwrap().peer_fd.set(fd1.downgrade()).unwrap(); - fd1.downcast::<AnonSocket>().unwrap().peer_fd.set(fd0.downgrade()).unwrap(); + fd0.peer_fd.set(FileDescriptionRef::downgrade(&fd1)).unwrap(); + fd1.peer_fd.set(FileDescriptionRef::downgrade(&fd0)).unwrap(); // Insert the file description to the fd table, generating the file descriptors. let sv0 = fds.insert(fd0); @@ -511,8 +491,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { }); // Make the file descriptions point to each other. - fd0.downcast::<AnonSocket>().unwrap().peer_fd.set(fd1.downgrade()).unwrap(); - fd1.downcast::<AnonSocket>().unwrap().peer_fd.set(fd0.downgrade()).unwrap(); + fd0.peer_fd.set(FileDescriptionRef::downgrade(&fd1)).unwrap(); + fd1.peer_fd.set(FileDescriptionRef::downgrade(&fd0)).unwrap(); // Insert the file description to the fd table, generating the file descriptors. let pipefd0 = fds.insert(fd0); diff --git a/src/tools/miri/src/shims/windows/handle.rs b/src/tools/miri/src/shims/windows/handle.rs index 3d872b65a63..c4eb11fbd3f 100644 --- a/src/tools/miri/src/shims/windows/handle.rs +++ b/src/tools/miri/src/shims/windows/handle.rs @@ -97,7 +97,7 @@ impl Handle { // packs the data into the lower `data_size` bits // and packs the discriminant right above the data - discriminant << data_size | data + (discriminant << data_size) | data } fn new(discriminant: u32, data: u32) -> Option<Self> { diff --git a/src/tools/miri/src/shims/windows/sync.rs b/src/tools/miri/src/shims/windows/sync.rs index a394e0430bc..4001201bf67 100644 --- a/src/tools/miri/src/shims/windows/sync.rs +++ b/src/tools/miri/src/shims/windows/sync.rs @@ -111,7 +111,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { pending_place: MPlaceTy<'tcx>, dest: MPlaceTy<'tcx>, } - @unblock = |this| { + |this, unblock: UnblockKind| { + assert_eq!(unblock, UnblockKind::Ready); let ret = this.init_once_try_begin(id, &pending_place, &dest)?; assert!(ret, "we were woken up but init_once_try_begin still failed"); interp_ok(()) diff --git a/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs b/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs index 3a207b7d50a..d9f1b27bf55 100644 --- a/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs +++ b/src/tools/miri/test-cargo-miri/no-std-smoke/src/main.rs @@ -1,6 +1,5 @@ // Copied from tests/pass/no-std.rs -#![feature(start)] #![no_std] // Plumbing to let us use `writeln!` to host stdout: @@ -22,8 +21,8 @@ impl Write for Host { } } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +fn miri_start(_: isize, _: *const *const u8) -> isize { writeln!(Host, "hello, world!").unwrap(); 0 } diff --git a/src/tools/miri/tests/fail-dep/libc/affinity.rs b/src/tools/miri/tests/fail-dep/libc/affinity.rs index 09f096e46f1..3acbd83d0e5 100644 --- a/src/tools/miri/tests/fail-dep/libc/affinity.rs +++ b/src/tools/miri/tests/fail-dep/libc/affinity.rs @@ -1,5 +1,4 @@ -//@ignore-target: windows # only very limited libc on Windows -//@ignore-target: apple # `sched_setaffinity` is not supported on macOS +//@only-target: linux # these are Linux-specific APIs //@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4 fn main() { diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs index 81a96103db4..0d893663fd6 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_read_twice.rs @@ -1,4 +1,4 @@ -//@only-target: linux +//@only-target: linux android illumos //~^ERROR: deadlocked //~^^ERROR: deadlocked //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs index 7a2a6f4eb1a..9fed47c17d4 100644 --- a/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs +++ b/src/tools/miri/tests/fail-dep/libc/eventfd_block_write_twice.rs @@ -1,4 +1,4 @@ -//@only-target: linux +//@only-target: linux android illumos //~^ERROR: deadlocked //~^^ERROR: deadlocked //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs index 7bef687e339..45f6bf6da09 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc-epoll-data-race.rs @@ -2,7 +2,7 @@ //! and we only read one of them, we do not synchronize with the other events //! and therefore still report a data race for things that need to see the second event //! to be considered synchronized. -//@only-target: linux android +//@only-target: linux android illumos // ensure deterministic schedule //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs index 1c6c2f70c1d..059b24cb8c0 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_block_two_thread.rs @@ -1,7 +1,7 @@ //@compile-flags: -Zmiri-preemption-rate=0 //~^ERROR: deadlocked //~^^ERROR: deadlocked -//@only-target: linux +//@only-target: linux android illumos //@error-in-other-file: deadlock use std::convert::TryInto; diff --git a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs index 03d4b2d6633..59cf0fc2ba0 100644 --- a/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs +++ b/src/tools/miri/tests/fail-dep/libc/libc_epoll_unsupported_fd.rs @@ -1,4 +1,4 @@ -//@only-target: linux +//@only-target: linux android illumos // This is a test for registering unsupported fd with epoll. // Register epoll fd with epoll is allowed in real system, but we do not support this. diff --git a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs index 8b34ff4ac2e..a1d8fd663f8 100644 --- a/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs +++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs @@ -1,9 +1,8 @@ -//@ignore-target: windows # No `memrchr` on Windows -//@ignore-target: apple # No `memrchr` on some apple targets +//@only-target: linux # `memrchr` is a GNU extension use std::ptr; -// null is explicitly called out as UB in the C docs. +// null is explicitly called out as UB in the C docs for `memchr`. fn main() { unsafe { libc::memrchr(ptr::null(), 0, 0); //~ERROR: null pointer diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs new file mode 100644 index 00000000000..8413e118819 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.rs @@ -0,0 +1,37 @@ +//! This is a regression test for <https://github.com/rust-lang/miri/issues/3947>: we had some +//! faulty logic around `release_clock` that led to this code not reporting a data race. +//~^^ERROR: deadlock +//@ignore-target: windows # no libc socketpair on Windows +//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-address-reuse-rate=0 +//@error-in-other-file: deadlock +use std::thread; + +fn main() { + let mut fds = [-1, -1]; + let res = unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, fds.as_mut_ptr()) }; + assert_eq!(res, 0); + + let thread1 = thread::spawn(move || { + let mut buf: [u8; 1] = [0; 1]; + let _res: i32 = unsafe { + libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) //~ERROR: deadlock + .try_into() + .unwrap() + }; + }); + let thread2 = thread::spawn(move || { + // Close the FD that the other thread is blocked on. + unsafe { libc::close(fds[1]) }; + }); + + // Run the other threads. + thread::yield_now(); + + // When they are both done, continue here. + let data = "a".as_bytes().as_ptr(); + let res = unsafe { libc::write(fds[0], data as *const libc::c_void, 1) }; + assert_eq!(res, -1); + + thread1.join().unwrap(); + thread2.join().unwrap(); +} diff --git a/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr new file mode 100644 index 00000000000..fe196f5d7d7 --- /dev/null +++ b/src/tools/miri/tests/fail-dep/libc/socketpair-close-while-blocked.stderr @@ -0,0 +1,35 @@ +error: deadlock: the evaluated program deadlocked + --> RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + | +LL | let ret = unsafe { libc::pthread_join(id, ptr::null_mut()) }; + | ^ the evaluated program deadlocked + | + = note: BACKTRACE: + = note: inside `std::sys::pal::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/pal/PLATFORM/thread.rs:LL:CC + = note: inside `std::thread::JoinInner::<'_, ()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC +note: inside `main` + --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC + | +LL | thread1.join().unwrap(); + | ^^^^^^^^^^^^^^ + +error: deadlock: the evaluated program deadlocked + --> tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC + | +LL | libc::read(fds[1], buf.as_mut_ptr().cast(), buf.len() as libc::size_t) + | ^ the evaluated program deadlocked + | + = note: BACKTRACE on thread `unnamed-ID`: + = note: inside closure at tests/fail-dep/libc/socketpair-close-while-blocked.rs:LL:CC + +error: deadlock: the evaluated program deadlocked + | + = note: the evaluated program deadlocked + = note: (no span available) + = note: BACKTRACE on thread `unnamed-ID`: + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 3 previous errors + diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs index babdb73f093..8d41002735c 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.rs @@ -1,8 +1,9 @@ //@compile-flags: -Cpanic=abort -#![feature(start, core_intrinsics)] +#![feature(core_intrinsics)] #![feature(alloc_error_handler)] #![feature(allocator_api)] #![no_std] +#![no_main] extern crate alloc; @@ -43,7 +44,7 @@ mod plumbing { static GLOBAL: NoAlloc = NoAlloc; } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { handle_alloc_error(Layout::for_value(&0)); } diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr index d12e119bce3..1a9e7574339 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_custom.stderr @@ -16,7 +16,7 @@ LL | fn alloc_error_handler(layout: Layout) -> ! { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `start` +note: inside `miri_start` --> tests/fail/alloc/alloc_error_handler_custom.rs:LL:CC | LL | handle_alloc_error(Layout::for_value(&0)); diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs index 18a8a61f22f..f73f8e3e7e1 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.rs @@ -1,8 +1,9 @@ //@compile-flags: -Cpanic=abort -#![feature(start, core_intrinsics)] +#![feature(core_intrinsics)] #![feature(alloc_error_handler)] #![feature(allocator_api)] #![no_std] +#![no_main] extern crate alloc; @@ -41,7 +42,7 @@ mod plumbing { static GLOBAL: NoAlloc = NoAlloc; } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { handle_alloc_error(Layout::for_value(&0)); } diff --git a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr index f495d65a8b0..6b4266b9a8b 100644 --- a/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr +++ b/src/tools/miri/tests/fail/alloc/alloc_error_handler_no_std.stderr @@ -12,7 +12,7 @@ LL | core::intrinsics::abort(); = note: inside `alloc::alloc::__alloc_error_handler::__rdl_oom` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::handle_alloc_error::rt_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::handle_alloc_error` at RUSTLIB/alloc/src/alloc.rs:LL:CC -note: inside `start` +note: inside `miri_start` --> tests/fail/alloc/alloc_error_handler_no_std.rs:LL:CC | LL | handle_alloc_error(Layout::for_value(&0)); diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.rs b/src/tools/miri/tests/fail/alloc/no_global_allocator.rs index 0952b2c46ba..f76aebaa3e3 100644 --- a/src/tools/miri/tests/fail/alloc/no_global_allocator.rs +++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.rs @@ -2,15 +2,15 @@ //@normalize-stderr-test: "OS `.*`" -> "$$OS" // Make sure we pretend the allocation symbols don't exist when there is no allocator -#![feature(start)] #![no_std] +#![no_main] extern "Rust" { fn __rust_alloc(size: usize, align: usize) -> *mut u8; } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { unsafe { __rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function `__rust_alloc` } diff --git a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr index e08a747f7fa..541af64b894 100644 --- a/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr +++ b/src/tools/miri/tests/fail/alloc/no_global_allocator.stderr @@ -7,7 +7,7 @@ LL | __rust_alloc(1, 1); = help: if this is a basic API commonly used on this target, please report an issue with Miri = help: however, note that Miri does not aim to support every FFI function out there; for instance, we will not support APIs for things such as GUIs, scripting languages, or databases = note: BACKTRACE: - = note: inside `start` at tests/fail/alloc/no_global_allocator.rs:LL:CC + = note: inside `miri_start` at tests/fail/alloc/no_global_allocator.rs:LL:CC error: aborting due to 1 previous error diff --git a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs index 9c73bdc17be..791ffa7343d 100644 --- a/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs +++ b/src/tools/miri/tests/fail/intrinsics/copy_overlapping.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); -} +#[rustc_intrinsic] +unsafe fn copy_nonoverlapping<T>(_src: *const T, _dst: *mut T, _count: usize); fn main() { let mut data = [0u8; 16]; diff --git a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs index 281217f06f5..9a82c69fba8 100644 --- a/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs +++ b/src/tools/miri/tests/fail/intrinsics/copy_unaligned.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize); -} +#[rustc_intrinsic] +unsafe fn copy_nonoverlapping<T>(_src: *const T, _dst: *mut T, _count: usize); fn main() { let mut data = [0u16; 8]; diff --git a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs index 0b34afc6090..e42811d9e13 100644 --- a/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs +++ b/src/tools/miri/tests/fail/intrinsics/ctlz_nonzero.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] mod rusti { - extern "rust-intrinsic" { - pub fn ctlz_nonzero<T>(x: T) -> u32; - } + #[rustc_intrinsic] + pub unsafe fn ctlz_nonzero<T>(_x: T) -> u32; } pub fn main() { diff --git a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs index e220411f585..a1f7a5881d4 100644 --- a/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs +++ b/src/tools/miri/tests/fail/intrinsics/cttz_nonzero.rs @@ -1,9 +1,9 @@ + #![feature(intrinsics)] mod rusti { - extern "rust-intrinsic" { - pub fn cttz_nonzero<T>(x: T) -> u32; - } + #[rustc_intrinsic] + pub unsafe fn cttz_nonzero<T>(_x: T) -> u32; } pub fn main() { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs index a57845426d5..d75046ff360 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_inf1.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs index d383fc5b50a..8d343cdc1bd 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_infneg1.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs index a39a5066b6f..737a6fbafe0 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nan.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs index 71436eb3ba8..a1c307efc93 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_nanneg.rs @@ -1,9 +1,9 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; + fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs index 98ba964e47c..4bb5ded1033 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_neg.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs index 424b8fd965e..6b42ae56ece 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big1.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs index 5c50926c4df..81019a1c608 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_big2.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs index e0abd19d03f..24896bcae51 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_32_too_small1.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs index f5f842e58ec..fbb67d28fed 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_inf1.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs index 244c25b31cb..284b429230d 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg1.rs @@ -1,9 +1,9 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; + fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs index f7a663d12a5..2770dea4406 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_infneg2.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs index 171cbcc5934..1272566c07c 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_nan.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs index 40b67e173b9..a1165794982 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_neg.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs index e785123c4ca..0e68f4eaff7 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big1.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs index 4bf31d8ac02..ad3ac16dc6f 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big2.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs index 9775a56724b..1addb9fb1d7 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big3.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs index 53ff06e1e46..a04c29c37da 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big4.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs index 44356ff1771..32bdcd07073 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big5.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs index 66f5be96bfd..861af44a66f 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big6.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs index 18b380e8575..3b3e208f32f 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_big7.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs index 2a23b1dc8a4..81ca766de47 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small1.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs index 7fc3effda5d..2b437f38552 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small2.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs index 2a8f9c36642..94ee572f4d0 100644 --- a/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs +++ b/src/tools/miri/tests/fail/intrinsics/float_to_int_64_too_small3.rs @@ -1,9 +1,8 @@ #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd -extern "rust-intrinsic" { - fn float_to_int_unchecked<Float: Copy, Int: Copy>(value: Float) -> Int; -} +#[rustc_intrinsic] +unsafe fn float_to_int_unchecked<Float: Copy, Int: Copy>(_value: Float) -> Int; fn main() { unsafe { diff --git a/src/tools/miri/tests/fail/panic/no_std.rs b/src/tools/miri/tests/fail/panic/no_std.rs index 4d32b6d7461..cd8a3251fef 100644 --- a/src/tools/miri/tests/fail/panic/no_std.rs +++ b/src/tools/miri/tests/fail/panic/no_std.rs @@ -1,14 +1,15 @@ //@compile-flags: -Cpanic=abort -#![feature(start, core_intrinsics)] +#![feature(core_intrinsics)] #![no_std] +#![no_main] use core::fmt::Write; #[path = "../../utils/mod.no_std.rs"] mod utils; -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { panic!("blarg I am dead") } diff --git a/src/tools/miri/tests/fail/panic/no_std.stderr b/src/tools/miri/tests/fail/panic/no_std.stderr index c1cd53e310f..d54f2a58776 100644 --- a/src/tools/miri/tests/fail/panic/no_std.stderr +++ b/src/tools/miri/tests/fail/panic/no_std.stderr @@ -8,7 +8,7 @@ LL | core::intrinsics::abort(); | = note: BACKTRACE: = note: inside `panic_handler` at tests/fail/panic/no_std.rs:LL:CC -note: inside `start` +note: inside `miri_start` --> tests/fail/panic/no_std.rs:LL:CC | LL | panic!("blarg I am dead") diff --git a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs index 3c4311efc4c..400e3ca3d7d 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-affinity.rs @@ -1,5 +1,4 @@ -//@ignore-target: windows # only very limited libc on Windows -//@ignore-target: apple # `sched_{g, s}etaffinity` are not supported on macOS +//@only-target: linux # these are Linux-specific APIs //@compile-flags: -Zmiri-disable-isolation -Zmiri-num-cpus=4 #![feature(io_error_more)] #![feature(pointer_is_aligned_to)] diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs index e3c42b2701c..825e1355848 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-blocking.rs @@ -1,4 +1,4 @@ -//@only-target: linux android +//@only-target: linux android illumos // test_epoll_block_then_unblock and test_epoll_race depend on a deterministic schedule. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs index 111e639c864..23e2122ee50 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-epoll-no-blocking.rs @@ -1,4 +1,4 @@ -//@only-target: linux android +//@only-target: linux android illumos use std::convert::TryInto; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs index 2e453215ec9..30e1bbb8fa1 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-eventfd.rs @@ -1,4 +1,4 @@ -//@only-target: linux android +//@only-target: linux android illumos // test_race, test_blocking_read and test_blocking_write depend on a deterministic schedule. //@compile-flags: -Zmiri-preemption-rate=0 @@ -10,7 +10,10 @@ use std::thread; fn main() { test_read_write(); test_race(); + + #[cfg(not(target_os = "illumos"))] test_syscall(); + test_blocking_read(); test_blocking_write(); test_two_threads_blocked_on_eventfd(); @@ -115,6 +118,8 @@ fn test_race() { } // This is a test for calling eventfd2 through a syscall. +// Illumos supports eventfd, but it has no entry to call it through syscall. +#[cfg(not(target_os = "illumos"))] fn test_syscall() { let initval = 0 as libc::c_uint; let flags = (libc::EFD_CLOEXEC | libc::EFD_NONBLOCK) as libc::c_int; diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs index f85abe2cc43..129b18d8e59 100644 --- a/src/tools/miri/tests/pass-dep/libc/libc-fs.rs +++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs @@ -38,6 +38,8 @@ fn main() { test_isatty(); test_read_and_uninit(); test_nofollow_not_symlink(); + #[cfg(target_os = "macos")] + test_ioctl(); } fn test_file_open_unix_allow_two_args() { @@ -431,3 +433,21 @@ fn test_nofollow_not_symlink() { let ret = unsafe { libc::open(cpath.as_ptr(), libc::O_NOFOLLOW | libc::O_CLOEXEC) }; assert!(ret >= 0); } + +#[cfg(target_os = "macos")] +fn test_ioctl() { + let path = utils::prepare_with_content("miri_test_libc_ioctl.txt", &[]); + + let mut name = path.into_os_string(); + name.push("\0"); + let name_ptr = name.as_bytes().as_ptr().cast::<libc::c_char>(); + unsafe { + // 100 surely is an invalid FD. + assert_eq!(libc::ioctl(100, libc::FIOCLEX), -1); + let errno = std::io::Error::last_os_error().raw_os_error().unwrap(); + assert_eq!(errno, libc::EBADF); + + let fd = libc::open(name_ptr, libc::O_RDONLY); + assert_eq!(libc::ioctl(fd, libc::FIOCLEX), 0); + } +} diff --git a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs index cf634bc6890..6ac71b5ad1e 100644 --- a/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs +++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs @@ -29,12 +29,13 @@ fn main() { fn set_thread_name(name: &CStr) -> i32 { cfg_if::cfg_if! { - if #[cfg(any(target_os = "linux", target_os = "illumos", target_os = "solaris"))] { + if #[cfg(any( + target_os = "linux", + target_os = "freebsd", + target_os = "illumos", + target_os = "solaris" + ))] { unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) } - } else if #[cfg(target_os = "freebsd")] { - // pthread_set_name_np does not return anything - unsafe { libc::pthread_set_name_np(libc::pthread_self(), name.as_ptr().cast()) }; - 0 } else if #[cfg(target_os = "macos")] { unsafe { libc::pthread_setname_np(name.as_ptr().cast()) } } else { @@ -47,6 +48,7 @@ fn main() { cfg_if::cfg_if! { if #[cfg(any( target_os = "linux", + target_os = "freebsd", target_os = "illumos", target_os = "solaris", target_os = "macos" @@ -54,12 +56,6 @@ fn main() { unsafe { libc::pthread_getname_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len()) } - } else if #[cfg(target_os = "freebsd")] { - // pthread_get_name_np does not return anything - unsafe { - libc::pthread_get_name_np(libc::pthread_self(), name.as_mut_ptr().cast(), name.len()) - }; - 0 } else { compile_error!("get_thread_name not supported for this OS") } @@ -201,27 +197,25 @@ fn main() { .unwrap(); // Now set the name for a non-existing thread and verify error codes. - // (FreeBSD doesn't return an error code.) - #[cfg(not(target_os = "freebsd"))] - { - let invalid_thread = 0xdeadbeef; - let error = { - cfg_if::cfg_if! { - if #[cfg(target_os = "linux")] { - libc::ENOENT - } else { - libc::ESRCH - } + let invalid_thread = 0xdeadbeef; + let error = { + cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + libc::ENOENT + } else { + libc::ESRCH } - }; - #[cfg(not(target_os = "macos"))] - { - // macOS has no `setname` function accepting a thread id as the first argument. - let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) }; - assert_eq!(res, error); } - let mut buf = [0; 64]; - let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) }; + }; + + #[cfg(not(target_os = "macos"))] + { + // macOS has no `setname` function accepting a thread id as the first argument. + let res = unsafe { libc::pthread_setname_np(invalid_thread, [0].as_ptr()) }; assert_eq!(res, error); } + + let mut buf = [0; 64]; + let res = unsafe { libc::pthread_getname_np(invalid_thread, buf.as_mut_ptr(), buf.len()) }; + assert_eq!(res, error); } diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.rs b/src/tools/miri/tests/pass/alloc-access-tracking.rs index 50e217918b0..c47063bef03 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.rs +++ b/src/tools/miri/tests/pass/alloc-access-tracking.rs @@ -1,5 +1,5 @@ -#![feature(start)] #![no_std] +#![no_main] //@compile-flags: -Zmiri-track-alloc-id=21 -Zmiri-track-alloc-accesses -Cpanic=abort //@normalize-stderr-test: "id 21" -> "id $$ALLOC" //@only-target: linux # alloc IDs differ between OSes (due to extern static allocations) @@ -9,8 +9,8 @@ extern "Rust" { fn miri_dealloc(ptr: *mut u8, size: usize, align: usize); } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { unsafe { let ptr = miri_alloc(123, 1); *ptr = 42; // Crucially, only a write is printed here, no read! diff --git a/src/tools/miri/tests/pass/alloc-access-tracking.stderr b/src/tools/miri/tests/pass/alloc-access-tracking.stderr index 451f5de25d3..0c85afd831b 100644 --- a/src/tools/miri/tests/pass/alloc-access-tracking.stderr +++ b/src/tools/miri/tests/pass/alloc-access-tracking.stderr @@ -5,7 +5,7 @@ LL | let ptr = miri_alloc(123, 1); | ^^^^^^^^^^^^^^^^^^ created Miri bare-metal heap allocation of 123 bytes (alignment ALIGN bytes) with id $ALLOC | = note: BACKTRACE: - = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC + = note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC note: tracking was triggered --> tests/pass/alloc-access-tracking.rs:LL:CC @@ -14,7 +14,7 @@ LL | *ptr = 42; // Crucially, only a write is printed here, no read! | ^^^^^^^^^ write access to allocation with id $ALLOC | = note: BACKTRACE: - = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC + = note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC note: tracking was triggered --> tests/pass/alloc-access-tracking.rs:LL:CC @@ -23,7 +23,7 @@ LL | assert_eq!(*ptr, 42); | ^^^^^^^^^^^^^^^^^^^^ read access to allocation with id $ALLOC | = note: BACKTRACE: - = note: inside `start` at RUSTLIB/core/src/macros/mod.rs:LL:CC + = note: inside `miri_start` at RUSTLIB/core/src/macros/mod.rs:LL:CC = note: this note originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) note: tracking was triggered @@ -33,5 +33,5 @@ LL | miri_dealloc(ptr, 123, 1); | ^^^^^^^^^^^^^^^^^^^^^^^^^ freed allocation with id $ALLOC | = note: BACKTRACE: - = note: inside `start` at tests/pass/alloc-access-tracking.rs:LL:CC + = note: inside `miri_start` at tests/pass/alloc-access-tracking.rs:LL:CC diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs index acd3502f528..0d0d79098d5 100644 --- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs +++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs @@ -14,10 +14,9 @@ use std::ptr; use std::simd::StdFloat; use std::simd::prelude::*; -extern "rust-intrinsic" { - #[rustc_nounwind] - pub fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U; -} +#[rustc_intrinsic] +#[rustc_nounwind] +pub unsafe fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(_x: T, _y: T) -> U; fn simd_ops_f32() { let a = f32x4::splat(10.0); diff --git a/src/tools/miri/tests/pass/miri-alloc.rs b/src/tools/miri/tests/pass/miri-alloc.rs index 17f6d5d05a5..20269d8ced0 100644 --- a/src/tools/miri/tests/pass/miri-alloc.rs +++ b/src/tools/miri/tests/pass/miri-alloc.rs @@ -1,5 +1,5 @@ -#![feature(start)] #![no_std] +#![no_main] //@compile-flags: -Cpanic=abort // windows tls dtors go through libstd right now, thus this test // cannot pass. When windows tls dtors go through the special magic @@ -11,8 +11,8 @@ extern "Rust" { fn miri_dealloc(ptr: *mut u8, size: usize, align: usize); } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { unsafe { let ptr = miri_alloc(123, 1); core::ptr::write_bytes(ptr, 0u8, 123); diff --git a/src/tools/miri/tests/pass/miri_start.stdout b/src/tools/miri/tests/pass/miri_start.stdout deleted file mode 100644 index 1c9e8489b57..00000000000 --- a/src/tools/miri/tests/pass/miri_start.stdout +++ /dev/null @@ -1 +0,0 @@ -Hello from miri_start! diff --git a/src/tools/miri/tests/pass/no_std.rs b/src/tools/miri/tests/pass/no_std.rs deleted file mode 100644 index fc1c16f5fb9..00000000000 --- a/src/tools/miri/tests/pass/no_std.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@compile-flags: -Cpanic=abort -#![feature(start)] -#![no_std] - -use core::fmt::Write; - -#[path = "../utils/mod.no_std.rs"] -mod utils; - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - writeln!(utils::MiriStdout, "hello, world!").unwrap(); - 0 -} - -#[panic_handler] -fn panic_handler(_: &core::panic::PanicInfo) -> ! { - loop {} -} diff --git a/src/tools/miri/tests/pass/miri_start.rs b/src/tools/miri/tests/pass/no_std_miri_start.rs index 756a1f60be1..cf9636b9d8c 100644 --- a/src/tools/miri/tests/pass/miri_start.rs +++ b/src/tools/miri/tests/pass/no_std_miri_start.rs @@ -1,6 +1,6 @@ //@compile-flags: -Cpanic=abort -#![no_main] #![no_std] +#![no_main] use core::fmt::Write; @@ -9,7 +9,7 @@ mod utils; #[no_mangle] fn miri_start(_argc: isize, _argv: *const *const u8) -> isize { - writeln!(utils::MiriStdout, "Hello from miri_start!").unwrap(); + writeln!(utils::MiriStdout, "hello, world!").unwrap(); 0 } diff --git a/src/tools/miri/tests/pass/no_std.stdout b/src/tools/miri/tests/pass/no_std_miri_start.stdout index 270c611ee72..270c611ee72 100644 --- a/src/tools/miri/tests/pass/no_std.stdout +++ b/src/tools/miri/tests/pass/no_std_miri_start.stdout diff --git a/src/tools/miri/tests/pass/shims/pipe.rs b/src/tools/miri/tests/pass/shims/pipe.rs new file mode 100644 index 00000000000..1be29886d2d --- /dev/null +++ b/src/tools/miri/tests/pass/shims/pipe.rs @@ -0,0 +1,13 @@ +//@ignore-target: windows + +#![feature(anonymous_pipe)] + +use std::io::{Read, Write, pipe}; + +fn main() { + let (mut ping_rx, mut ping_tx) = pipe().unwrap(); + ping_tx.write(b"hello").unwrap(); + let mut buf: [u8; 5] = [0; 5]; + ping_rx.read(&mut buf).unwrap(); + assert_eq!(&buf, "hello".as_bytes()); +} diff --git a/src/tools/miri/tests/pass/start.rs b/src/tools/miri/tests/pass/start.rs deleted file mode 100644 index f25d62fa8c3..00000000000 --- a/src/tools/miri/tests/pass/start.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(start)] - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - println!("Hello from start!"); - - 0 -} diff --git a/src/tools/miri/tests/pass/start.stdout b/src/tools/miri/tests/pass/start.stdout deleted file mode 100644 index d7f627d237c..00000000000 --- a/src/tools/miri/tests/pass/start.stdout +++ /dev/null @@ -1 +0,0 @@ -Hello from start! diff --git a/src/tools/miri/triagebot.toml b/src/tools/miri/triagebot.toml index 3192882dff6..4e013764d87 100644 --- a/src/tools/miri/triagebot.toml +++ b/src/tools/miri/triagebot.toml @@ -1,3 +1,6 @@ +## See <https://forge.rust-lang.org/triagebot/index.html> for documentation +## of these options. + [relabel] allow-unauthenticated = [ "A-*", @@ -30,5 +33,10 @@ remove_labels = ["S-waiting-on-author"] # Those labels are added when PR author requests a review from an assignee add_labels = ["S-waiting-on-review"] +[merge-conflicts] +remove = [] +add = ["S-waiting-on-author"] +unless = ["S-blocked", "S-waiting-on-team", "S-waiting-on-review"] + # Automatically close and reopen PRs made by bots to run CI on them [bot-pull-requests] diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs index 06ed076a864..8b3bd77141b 100644 --- a/src/tools/opt-dist/src/tests.rs +++ b/src/tools/opt-dist/src/tests.rs @@ -69,6 +69,7 @@ change-id = 115898 [rust] channel = "{channel}" +verbose-tests = true [build] rustc = "{rustc}" @@ -102,13 +103,19 @@ llvm-config = "{llvm_config}" "tests/incremental", "tests/mir-opt", "tests/pretty", + "tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu", "tests/ui", "tests/crashes", ]; for test_path in env.skipped_tests() { args.extend(["--skip", test_path]); } - cmd(&args).env("COMPILETEST_FORCE_STAGE0", "1").run().context("Cannot execute tests") + cmd(&args) + .env("COMPILETEST_FORCE_STAGE0", "1") + // Also run dist-only tests + .env("COMPILETEST_ENABLE_DIST_TESTS", "1") + .run() + .context("Cannot execute tests") } /// Tries to find the version of the dist artifacts (either nightly, beta, or 1.XY.Z). diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index e73413085fa..b4dc753ab53 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -151,6 +151,61 @@ impl Command { self } + /// Set an auxiliary stream passed to the process, besides the stdio streams. + /// + /// # Notes + /// + /// Use with caution! Ideally, only set one aux fd; if there are multiple, their old `fd` may + /// overlap with another's `new_fd`, and may break. The caller must make sure this is not the + /// case. This function is only "safe" because the safety requirements are practically not + /// possible to uphold. + #[cfg(unix)] + pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>( + &mut self, + new_fd: std::os::fd::RawFd, + fd: F, + ) -> &mut Self { + use std::mem; + // NOTE: If more than 1 auxiliary file descriptor is needed, this function should be + // rewritten. + use std::os::fd::AsRawFd; + use std::os::unix::process::CommandExt; + + let cvt = |x| if x == -1 { Err(std::io::Error::last_os_error()) } else { Ok(()) }; + + // Ensure fd stays open until the fork. + let fd = mem::ManuallyDrop::new(fd.into()); + let fd = fd.as_raw_fd(); + + if fd == new_fd { + // If the new file descriptor is already the same as fd, just turn off `FD_CLOEXEC`. + let fd_flags = { + let ret = unsafe { libc::fcntl(fd, libc::F_GETFD, 0) }; + if ret < 0 { + panic!("failed to read fd flags: {}", std::io::Error::last_os_error()); + } + ret + }; + // Clear `FD_CLOEXEC`. + let fd_flags = fd_flags & !libc::FD_CLOEXEC; + + // SAFETY(io-safety): `fd` is already owned. + cvt(unsafe { libc::fcntl(fd, libc::F_SETFD, fd_flags as libc::c_int) }) + .expect("disabling CLOEXEC failed"); + } + let pre_exec = move || { + if fd.as_raw_fd() != new_fd { + // SAFETY(io-safety): it's the caller's responsibility that we won't override the + // target fd. + cvt(unsafe { libc::dup2(fd, new_fd) })?; + } + Ok(()) + }; + // SAFETY(pre-exec-safe): `dup2` is pre-exec-safe. + unsafe { self.cmd.pre_exec(pre_exec) }; + self + } + /// Run the constructed command and assert that it is successfully run. /// /// By default, std{in,out,err} are [`Stdio::piped()`]. diff --git a/src/tools/run-make-support/src/macros.rs b/src/tools/run-make-support/src/macros.rs index cc3d1281d0a..94955aefe57 100644 --- a/src/tools/run-make-support/src/macros.rs +++ b/src/tools/run-make-support/src/macros.rs @@ -104,6 +104,17 @@ macro_rules! impl_common_helpers { self } + /// Set an auxiliary stream passed to the process, besides the stdio streams. + #[cfg(unix)] + pub fn set_aux_fd<F: Into<std::os::fd::OwnedFd>>( + &mut self, + new_fd: std::os::fd::RawFd, + fd: F, + ) -> &mut Self { + self.cmd.set_aux_fd(new_fd, fd); + self + } + /// Run the constructed command and assert that it is successfully run. #[track_caller] pub fn run(&mut self) -> crate::command::CompletedProcess { diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 48b5f3aabfc..f92668a6a97 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -98,9 +98,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" [[package]] name = "borsh" @@ -194,9 +194,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chalk-derive" -version = "0.98.0" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9426c8fd0fe61c3da880b801d3b510524df17843a8f9ec1f5b9cec24fb7412df" +checksum = "572583d9b97f9d277e5c7607f8239a30e2e04d3ed3b47c87d1cb2152ae724073" dependencies = [ "proc-macro2", "quote", @@ -206,19 +206,19 @@ dependencies = [ [[package]] name = "chalk-ir" -version = "0.98.0" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f2eb1cd6054da221bd1ac0197fb2fe5e2caf3dcb93619398fc1433f8f09093" +checksum = "e60e0ef9c81dce1336a9ed3c76f08775f5b623151d96d85ba45f7b10de76d1c7" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "chalk-derive", ] [[package]] name = "chalk-recursive" -version = "0.98.0" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129dc03458f71cfb9c3cd621c9c68166a94e87b85b16ccd29af015d7ff9a1c61" +checksum = "5a06350d614e22b03a69b8105e3541614450a7ea48bc58ecc6c6bd92731a3995" dependencies = [ "chalk-derive", "chalk-ir", @@ -229,9 +229,9 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.98.0" +version = "0.99.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7e8a8c1e928f98cdf227b868416ef21dcd8cc3c61b347576d783713444d41c8" +checksum = "0e428761e9b55bee516bfe2457caed8b6d1b86353f92ae825bbe438a36ce91e8" dependencies = [ "chalk-derive", "chalk-ir", @@ -523,6 +523,7 @@ dependencies = [ "hir-def", "hir-expand", "hir-ty", + "indexmap", "intern", "itertools", "rustc-hash 2.0.0", @@ -544,7 +545,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.6.0", + "bitflags 2.7.0", "cfg", "cov-mark", "dashmap", @@ -610,7 +611,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.6.0", + "bitflags 2.7.0", "chalk-derive", "chalk-ir", "chalk-recursive", @@ -734,7 +735,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "base-db", - "bitflags 2.6.0", + "bitflags 2.7.0", "cov-mark", "crossbeam-channel", "either", @@ -820,11 +821,11 @@ dependencies = [ [[package]] name = "inotify" -version = "0.9.6" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.7.0", "inotify-sys", "libc", ] @@ -908,9 +909,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libloading" @@ -938,7 +939,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "libc", "redox_syscall", ] @@ -1117,14 +1118,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.11" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] @@ -1142,7 +1143,7 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "cfg-if", "cfg_aliases 0.1.1", "libc", @@ -1156,12 +1157,11 @@ checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] name = "notify" -version = "6.1.1" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943" dependencies = [ - "bitflags 2.6.0", - "crossbeam-channel", + "bitflags 2.7.0", "filetime", "fsevent-sys", "inotify", @@ -1169,11 +1169,18 @@ dependencies = [ "libc", "log", "mio", + "notify-types", "walkdir", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] +name = "notify-types" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d" + +[[package]] name = "nu-ansi-term" version = "0.50.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1371,6 +1378,7 @@ version = "0.0.0" dependencies = [ "expect-test", "intern", + "libc", "libloading", "memmap2", "object 0.33.0", @@ -1428,7 +1436,7 @@ dependencies = [ "libc", "perf-event", "tikv-jemalloc-ctl", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1482,7 +1490,7 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "memchr", "unicase", ] @@ -1507,20 +1515,20 @@ dependencies = [ [[package]] name = "ra-ap-rustc_abi" -version = "0.87.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b782af0a7a8df16ddf43cd70da9f17bc3b1ce712c9e4992b6edb16f5f53632" +checksum = "d5246e9e1f450333a990877eabbc36fe0567e7cedd56d5365db319e14079cf2a" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", "ra-ap-rustc_index", "tracing", ] [[package]] name = "ra-ap-rustc_index" -version = "0.87.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5742f134960482f543b35ecebec3cacc6d79a9a685713518b4d8d70c5f9aa8" +checksum = "59fd8e4f5b34c434ec111efb0e0614954db048b9307d3b2e4cc3c915da9d2160" dependencies = [ "ra-ap-rustc_index_macros", "smallvec", @@ -1528,9 +1536,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_index_macros" -version = "0.87.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7ea011fcf68309a8835ad01d91c032cb18444617b00e2cab21d45b208164441" +checksum = "2d34973fe081392bd1edb022e865e9952fcaa093f9cdae183edce64472e5e889" dependencies = [ "proc-macro2", "quote", @@ -1539,9 +1547,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_lexer" -version = "0.87.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb76f0a4d4c20859e41f0a23bff0f37ab9ca9171c214a6c7dd72ea69434865dc" +checksum = "52fa42c582e21b35e8f61a5afe3c63a9c722d995826762eb19b18beeccf5157f" dependencies = [ "unicode-properties", "unicode-xid", @@ -1549,9 +1557,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_parse_format" -version = "0.87.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06080bd35078305421a62da77f3c128482d8d44441b6da8ce9d146d1cd9cdb5b" +checksum = "740383328d7033393e5385f4a6073b880d5811b0fc0fd2559e481f905940f2f8" dependencies = [ "ra-ap-rustc_index", "ra-ap-rustc_lexer", @@ -1559,9 +1567,9 @@ dependencies = [ [[package]] name = "ra-ap-rustc_pattern_analysis" -version = "0.87.0" +version = "0.91.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a3154fe4c20c177d7b3c678a2d3a97aba0cca156ddef88959915041889daf0" +checksum = "c39f544728f32cebffb1a8b92ba3c1f3dcb4144081438d192137ed197d479a9d" dependencies = [ "ra-ap-rustc_index", "rustc-hash 2.0.0", @@ -1626,7 +1634,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.7.0", ] [[package]] @@ -1713,7 +1721,7 @@ dependencies = [ "vfs", "vfs-notify", "walkdir", - "windows-sys 0.52.0", + "windows-sys 0.59.0", "xflags", "xshell", ] @@ -1936,7 +1944,7 @@ dependencies = [ "jod-thread", "libc", "miow", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index 9440123de70..1029844cd3a 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"] resolver = "2" [workspace.package] -rust-version = "1.82" +rust-version = "1.83" edition = "2021" license = "MIT OR Apache-2.0" authors = ["rust-analyzer team"] @@ -79,6 +79,7 @@ span = { path = "./crates/span", version = "0.0.0" } stdx = { path = "./crates/stdx", version = "0.0.0" } syntax = { path = "./crates/syntax", version = "0.0.0" } syntax-bridge = { path = "./crates/syntax-bridge", version = "0.0.0" } +test-fixture = { path = "./crates/test-fixture", version = "0.0.0" } test-utils = { path = "./crates/test-utils", version = "0.0.0" } toolchain = { path = "./crates/toolchain", version = "0.0.0" } tt = { path = "./crates/tt", version = "0.0.0" } @@ -86,16 +87,15 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" } vfs = { path = "./crates/vfs", version = "0.0.0" } edition = { path = "./crates/edition", version = "0.0.0" } -ra-ap-rustc_lexer = { version = "0.87", default-features = false } -ra-ap-rustc_parse_format = { version = "0.87", default-features = false } -ra-ap-rustc_index = { version = "0.87", default-features = false } -ra-ap-rustc_abi = { version = "0.87", default-features = false } -ra-ap-rustc_pattern_analysis = { version = "0.87", default-features = false } +ra-ap-rustc_lexer = { version = "0.91", default-features = false } +ra-ap-rustc_parse_format = { version = "0.91", default-features = false } +ra-ap-rustc_index = { version = "0.91", default-features = false } +ra-ap-rustc_abi = { version = "0.91", default-features = false } +ra-ap-rustc_pattern_analysis = { version = "0.91", default-features = false } # local crates that aren't published to crates.io. These should not have versions. -test-fixture = { path = "./crates/test-fixture" } -# In-tree crates that are published separately and follow semver. See lib/README.md +# in-tree crates that are published separately and follow semver. See lib/README.md line-index = { version = "0.1.2" } la-arena = { version = "0.3.1" } lsp-server = { version = "0.7.6" } @@ -106,10 +106,10 @@ arrayvec = "0.7.4" bitflags = "2.4.1" cargo_metadata = "0.18.1" camino = "1.1.6" -chalk-solve = { version = "0.98.0", default-features = false } -chalk-ir = "0.98.0" -chalk-recursive = { version = "0.98.0", default-features = false } -chalk-derive = "0.98.0" +chalk-solve = { version = "0.99.0", default-features = false } +chalk-ir = "0.99.0" +chalk-recursive = { version = "0.99.0", default-features = false } +chalk-derive = "0.99.0" crossbeam-channel = "0.5.8" dissimilar = "1.0.7" dot = "0.1.4" diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 0a9e83bc3ba..c7e4168f6bc 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -136,7 +136,7 @@ pub trait SourceRootDatabase: SourceDatabase { #[ra_salsa::input] fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; - /// Crates whose root fool is in `id`. + /// Crates whose root file is in `id`. fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>; } diff --git a/src/tools/rust-analyzer/crates/edition/src/lib.rs b/src/tools/rust-analyzer/crates/edition/src/lib.rs index c25d5b9557b..7e9c94af408 100644 --- a/src/tools/rust-analyzer/crates/edition/src/lib.rs +++ b/src/tools/rust-analyzer/crates/edition/src/lib.rs @@ -5,7 +5,8 @@ use std::fmt; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(u8)] pub enum Edition { - Edition2015, + // The syntax context stuff needs the discriminants to start from 0 and be consecutive. + Edition2015 = 0, Edition2018, Edition2021, Edition2024, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index 37e2a99e60f..710bffcefe9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -122,6 +122,11 @@ impl Attrs { AttrQuery { attrs: self, key } } + pub fn rust_analyzer_tool(&self) -> impl Iterator<Item = &Attr> { + self.iter() + .filter(|&attr| attr.path.segments().first().is_some_and(|s| *s == sym::rust_analyzer)) + } + pub fn cfg(&self) -> Option<CfgExpr> { let mut cfgs = self.by_key(&sym::cfg).tt_values().map(CfgExpr::parse); let first = cfgs.next()?; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index 433a956ff9a..de439249306 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -15,7 +15,7 @@ use hir_expand::{name::Name, ExpandError, InFile}; use la_arena::{Arena, ArenaMap, Idx, RawIdx}; use rustc_hash::FxHashMap; use smallvec::SmallVec; -use span::{Edition, MacroFileId}; +use span::{Edition, MacroFileId, SyntaxContextData}; use syntax::{ast, AstPtr, SyntaxNodePtr}; use triomphe::Arc; use tt::TextRange; @@ -37,15 +37,22 @@ use crate::{ /// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct HygieneId(pub(crate) span::SyntaxContextId); +pub struct HygieneId(span::SyntaxContextId); impl HygieneId { - pub const ROOT: Self = Self(span::SyntaxContextId::ROOT); + // The edition doesn't matter here, we only use this for comparisons and to lookup the macro. + pub const ROOT: Self = Self(span::SyntaxContextId::root(Edition::Edition2015)); - pub fn new(ctx: span::SyntaxContextId) -> Self { + pub fn new(mut ctx: span::SyntaxContextId) -> Self { + // See `Name` for why we're doing that. + ctx.remove_root_edition(); Self(ctx) } + pub(crate) fn lookup(self, db: &dyn DefDatabase) -> SyntaxContextData { + db.lookup_intern_syntax_context(self.0) + } + pub(crate) fn is_root(self) -> bool { self.0.is_root() } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index 10b84d041bd..1327bb3ab59 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -8,6 +8,7 @@ use std::mem; use base_db::CrateId; use either::Either; use hir_expand::{ + mod_path::tool_path, name::{AsName, Name}, span_map::{ExpansionSpanMap, SpanMap}, InFile, MacroDefId, @@ -27,6 +28,7 @@ use text_size::TextSize; use triomphe::Arc; use crate::{ + attr::Attrs, body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr}, builtin_type::BuiltinUint, data::adt::StructKind, @@ -212,6 +214,43 @@ impl ExprCollector<'_> { body: Option<ast::Expr>, is_async_fn: bool, ) -> (Body, BodySourceMap) { + let skip_body = match self.owner { + DefWithBodyId::FunctionId(it) => self.db.attrs(it.into()), + DefWithBodyId::StaticId(it) => self.db.attrs(it.into()), + DefWithBodyId::ConstId(it) => self.db.attrs(it.into()), + DefWithBodyId::InTypeConstId(_) => Attrs::EMPTY, + DefWithBodyId::VariantId(it) => self.db.attrs(it.into()), + } + .rust_analyzer_tool() + .any(|attr| *attr.path() == tool_path![skip]); + // If #[rust_analyzer::skip] annotated, only construct enough information for the signature + // and skip the body. + if skip_body { + self.body.body_expr = self.missing_expr(); + if let Some((param_list, mut attr_enabled)) = param_list { + if let Some(self_param) = + param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false)) + { + let is_mutable = + self_param.mut_token().is_some() && self_param.amp_token().is_none(); + let binding_id: la_arena::Idx<Binding> = self.alloc_binding( + Name::new_symbol_root(sym::self_.clone()), + BindingAnnotation::new(is_mutable, false), + ); + self.body.self_param = Some(binding_id); + self.source_map.self_param = + Some(self.expander.in_file(AstPtr::new(&self_param))); + } + self.body.params = param_list + .params() + .zip(attr_enabled) + .filter(|(_, enabled)| *enabled) + .map(|_| self.missing_pat()) + .collect(); + }; + return (self.body, self.source_map); + } + self.awaitable_context.replace(if is_async_fn { Awaitable::Yes } else { @@ -542,10 +581,7 @@ impl ExprCollector<'_> { let mutability = if raw_tok { if e.mut_token().is_some() { Mutability::Mut - } else if e.const_token().is_some() { - Mutability::Shared } else { - never!("parser only remaps to raw_token() if matching mutability token follows"); Mutability::Shared } } else { @@ -2460,7 +2496,7 @@ impl ExprCollector<'_> { None => HygieneId::ROOT, Some(span_map) => { let ctx = span_map.span_at(span_start).ctx; - HygieneId(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent) + HygieneId::new(self.db.lookup_intern_syntax_context(ctx).opaque_and_semitransparent) } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs index 63a7a9af201..08af470b965 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs @@ -345,7 +345,7 @@ mod tests { } } - fn do_check(ra_fixture: &str, expected: &[&str]) { + fn do_check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &[&str]) { let (offset, code) = extract_offset(ra_fixture); let code = { let mut buf = String::new(); @@ -509,7 +509,7 @@ fn foo() { ); } - fn do_check_local_name(ra_fixture: &str, expected_offset: u32) { + fn do_check_local_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_offset: u32) { let (db, position) = TestDB::with_position(ra_fixture); let file_id = position.file_id; let offset = position.offset; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs index 7e15a9f2d61..edc7c4c1f21 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs @@ -7,7 +7,7 @@ use crate::{test_db::TestDB, ModuleDefId}; use super::*; -fn lower(ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) { +fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) { let db = TestDB::with_files(ra_fixture); let krate = db.fetch_test_crate(); @@ -27,14 +27,14 @@ fn lower(ra_fixture: &str) -> (TestDB, Arc<Body>, DefWithBodyId) { (db, body, fn_def) } -fn def_map_at(ra_fixture: &str) -> String { +fn def_map_at(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { let (db, position) = TestDB::with_position(ra_fixture); let module = db.module_at_position(position); module.def_map(&db).dump(&db) } -fn check_block_scopes_at(ra_fixture: &str, expect: Expect) { +fn check_block_scopes_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, position) = TestDB::with_position(ra_fixture); let module = db.module_at_position(position); @@ -42,7 +42,7 @@ fn check_block_scopes_at(ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual); } -fn check_at(ra_fixture: &str, expect: Expect) { +fn check_at(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let actual = def_map_at(ra_fixture); expect.assert_eq(&actual); } @@ -444,3 +444,18 @@ fn foo() { }"# ); } + +#[test] +fn skip_skips_body() { + let (db, body, owner) = lower( + r#" +#[rust_analyzer::skip] +async fn foo(a: (), b: i32) -> u32 { + 0 + 1 + b() +} +"#, + ); + let printed = body.pretty_print(&db, owner, Edition::CURRENT); + expect!["fn foo(�: (), �: i32) -> impl ::core::future::Future::<Output = u32> �"] + .assert_eq(&printed); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index d85bc9a4320..12f5f6ad79a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -244,7 +244,7 @@ bitflags::bitflags! { #[derive(Debug, Clone, PartialEq, Eq)] pub struct TraitData { pub name: Name, - pub items: Vec<(Name, AssocItemId)>, + pub items: Box<[(Name, AssocItemId)]>, pub flags: TraitFlags, pub visibility: RawVisibility, // box it as the vec is usually empty anyways @@ -360,7 +360,7 @@ impl TraitAliasData { pub struct ImplData { pub target_trait: Option<TraitRef>, pub self_ty: TypeRefId, - pub items: Box<[AssocItemId]>, + pub items: Box<[(Name, AssocItemId)]>, pub is_negative: bool, pub is_unsafe: bool, // box it as the vec is usually empty anyways @@ -393,7 +393,6 @@ impl ImplData { collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items); let (items, macro_calls, diagnostics) = collector.finish(); - let items = items.into_iter().map(|(_, item)| item).collect(); ( Arc::new(ImplData { @@ -648,12 +647,12 @@ impl<'a> AssocItemCollector<'a> { fn finish( self, ) -> ( - Vec<(Name, AssocItemId)>, + Box<[(Name, AssocItemId)]>, Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, Vec<DefDiagnostic>, ) { ( - self.items, + self.items.into_boxed_slice(), if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) }, self.diagnostics, ) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs index 5315c1c6fbd..108258d5a11 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs @@ -10,7 +10,7 @@ use hir_expand::{ ExpandResult, HirFileId, InFile, Lookup, MacroCallId, }; use limit::Limit; -use span::SyntaxContextId; +use span::{Edition, SyntaxContextId}; use syntax::{ast, Parse}; use triomphe::Arc; @@ -60,7 +60,7 @@ impl Expander { pub fn syntax_context(&self) -> SyntaxContextId { // FIXME: - SyntaxContextId::ROOT + SyntaxContextId::root(Edition::CURRENT) } pub fn enter_expand<T: ast::AstNode>( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index a615abd1bbe..5d67902c8ac 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -665,7 +665,7 @@ mod tests { /// module the cursor is in. #[track_caller] fn check_found_path_( - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, path: &str, prefer_prelude: bool, prefer_absolute: bool, @@ -727,19 +727,35 @@ mod tests { expect.assert_eq(&res); } - fn check_found_path(ra_fixture: &str, path: &str, expect: Expect) { + fn check_found_path( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + path: &str, + expect: Expect, + ) { check_found_path_(ra_fixture, path, false, false, false, expect); } - fn check_found_path_prelude(ra_fixture: &str, path: &str, expect: Expect) { + fn check_found_path_prelude( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + path: &str, + expect: Expect, + ) { check_found_path_(ra_fixture, path, true, false, false, expect); } - fn check_found_path_absolute(ra_fixture: &str, path: &str, expect: Expect) { + fn check_found_path_absolute( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + path: &str, + expect: Expect, + ) { check_found_path_(ra_fixture, path, false, true, false, expect); } - fn check_found_path_prefer_no_std(ra_fixture: &str, path: &str, expect: Expect) { + fn check_found_path_prefer_no_std( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + path: &str, + expect: Expect, + ) { check_found_path_(ra_fixture, path, false, false, true, expect); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index 9574e5d9cd3..ac262950f13 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -509,7 +509,12 @@ mod tests { } } - fn check_search(ra_fixture: &str, crate_name: &str, query: Query, expect: Expect) { + fn check_search( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + crate_name: &str, + query: Query, + expect: Expect, + ) { let db = TestDB::with_files(ra_fixture); let crate_graph = db.crate_graph(); let krate = crate_graph @@ -587,7 +592,7 @@ mod tests { )) } - fn check(ra_fixture: &str, expect: Expect) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let db = TestDB::with_files(ra_fixture); let crate_graph = db.crate_graph(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs index 2c3eb5c8e5e..0fec7674109 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs @@ -162,6 +162,20 @@ impl ItemScope { .map(move |name| (name, self.get(name))) } + pub fn values(&self) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportId>)> + '_ { + self.values.iter().map(|(n, &i)| (n, i)) + } + + pub fn types( + &self, + ) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportOrExternCrate>)> + '_ { + self.types.iter().map(|(n, &i)| (n, i)) + } + + pub fn macros(&self) -> impl Iterator<Item = (&Name, Item<MacroId, ImportId>)> + '_ { + self.macros.iter().map(|(n, &i)| (n, i)) + } + pub fn imports(&self) -> impl Iterator<Item = ImportId> + '_ { self.use_imports_types .keys() @@ -263,11 +277,6 @@ impl ItemScope { self.unnamed_consts.iter().copied() } - /// Iterate over all module scoped macros - pub(crate) fn macros(&self) -> impl Iterator<Item = (&Name, MacroId)> + '_ { - self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) - } - /// Iterate over all legacy textual scoped macros visible at the end of the module pub fn legacy_macros(&self) -> impl Iterator<Item = (&Name, &[MacroId])> + '_ { self.legacy_macros.iter().map(|(name, def)| (name, &**def)) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs index 0f53969d6c7..80b699649fb 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs @@ -4,7 +4,7 @@ use test_fixture::WithFixture; use crate::{db::DefDatabase, test_db::TestDB}; -fn check(ra_fixture: &str, expect: Expect) { +fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, file_id) = TestDB::with_single_file(ra_fixture); let item_tree = db.file_item_tree(file_id.into()); let pretty = item_tree.pretty_print(&db, Edition::CURRENT); @@ -270,7 +270,7 @@ m!(); // AstId: 2 pub macro m2 { ... } - // AstId: 3, SyntaxContext: 0, ExpandTo: Items + // AstId: 3, SyntaxContext: 2, ExpandTo: Items m!(...); "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 0629d87e544..afdc49a2dc5 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -107,7 +107,7 @@ impl LangItems { for (_, module_data) in crate_def_map.modules() { for impl_def in module_data.scope.impls() { lang_items.collect_lang_item(db, impl_def, LangItemTarget::ImplDef); - for assoc in db.impl_data(impl_def).items.iter().copied() { + for &(_, assoc) in db.impl_data(impl_def).items.iter() { match assoc { AssocItemId::FunctionId(f) => { lang_items.collect_lang_item(db, f, LangItemTarget::Function) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 8af27513ebc..84c105a0a34 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -502,7 +502,7 @@ impl ModuleId { } /// Whether this module represents the crate root module - fn is_crate_root(&self) -> bool { + pub fn is_crate_root(&self) -> bool { self.local_id == DefMap::ROOT && self.block.is_none() } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index 511626b5ed9..8c5bd3b6d36 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -35,9 +35,9 @@ macro_rules! f { }; } -struct#0:1@58..64#1# MyTraitMap2#0:2@31..42#0# {#0:1@72..73#1# - map#0:1@86..89#1#:#0:1@89..90#1# #0:1@89..90#1#::#0:1@91..93#1#std#0:1@93..96#1#::#0:1@96..98#1#collections#0:1@98..109#1#::#0:1@109..111#1#HashSet#0:1@111..118#1#<#0:1@118..119#1#(#0:1@119..120#1#)#0:1@120..121#1#>#0:1@121..122#1#,#0:1@122..123#1# -}#0:1@132..133#1# +struct#0:1@58..64#4# MyTraitMap2#0:2@31..42#2# {#0:1@72..73#4# + map#0:1@86..89#4#:#0:1@89..90#4# #0:1@89..90#4#::#0:1@91..93#4#std#0:1@93..96#4#::#0:1@96..98#4#collections#0:1@98..109#4#::#0:1@109..111#4#HashSet#0:1@111..118#4#<#0:1@118..119#4#(#0:1@119..120#4#)#0:1@120..121#4#>#0:1@121..122#4#,#0:1@122..123#4# +}#0:1@132..133#4# "#]], ); } @@ -75,12 +75,12 @@ macro_rules! f { }; } -fn#0:2@30..32#0# main#0:2@33..37#0#(#0:2@37..38#0#)#0:2@38..39#0# {#0:2@40..41#0# - 1#0:2@50..51#0#;#0:2@51..52#0# - 1.0#0:2@61..64#0#;#0:2@64..65#0# - (#0:2@74..75#0#(#0:2@75..76#0#1#0:2@76..77#0#,#0:2@77..78#0# )#0:2@78..79#0#,#0:2@79..80#0# )#0:2@80..81#0#.#0:2@81..82#0#0#0:2@82..85#0#.#0:2@82..85#0#0#0:2@82..85#0#;#0:2@85..86#0# - let#0:2@95..98#0# x#0:2@99..100#0# =#0:2@101..102#0# 1#0:2@103..104#0#;#0:2@104..105#0# -}#0:2@110..111#0# +fn#0:2@30..32#2# main#0:2@33..37#2#(#0:2@37..38#2#)#0:2@38..39#2# {#0:2@40..41#2# + 1#0:2@50..51#2#;#0:2@51..52#2# + 1.0#0:2@61..64#2#;#0:2@64..65#2# + (#0:2@74..75#2#(#0:2@75..76#2#1#0:2@76..77#2#,#0:2@77..78#2# )#0:2@78..79#2#,#0:2@79..80#2# )#0:2@80..81#2#.#0:2@81..82#2#0#0:2@82..85#2#.#0:2@82..85#2#0#0:2@82..85#2#;#0:2@85..86#2# + let#0:2@95..98#2# x#0:2@99..100#2# =#0:2@101..102#2# 1#0:2@103..104#2#;#0:2@104..105#2# +}#0:2@110..111#2# "#]], @@ -171,7 +171,7 @@ fn main(foo: ()) { } fn main(foo: ()) { - /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#0#; + /* error: unresolved macro unresolved */"helloworld!"#0:3@236..321#2#; } } @@ -197,7 +197,7 @@ macro_rules! mk_struct { #[macro_use] mod foo; -struct#1:1@59..65#1# Foo#0:2@32..35#0#(#1:1@70..71#1#u32#0:2@41..44#0#)#1:1@74..75#1#;#1:1@75..76#1# +struct#1:1@59..65#4# Foo#0:2@32..35#2#(#1:1@70..71#4#u32#0:2@41..44#2#)#1:1@74..75#4#;#1:1@75..76#4# "#]], ); } @@ -423,10 +423,10 @@ m! { foo, bar } macro_rules! m { ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } ); } -impl#\1# Bar#\1# {#\1# - fn#\1# foo#\0#(#\1#)#\1# {#\1#}#\1# - fn#\1# bar#\0#(#\1#)#\1# {#\1#}#\1# -}#\1# +impl#\4# Bar#\4# {#\4# + fn#\4# foo#\2#(#\4#)#\4# {#\4#}#\4# + fn#\4# bar#\2#(#\4#)#\4# {#\4#}#\4# +}#\4# "#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 5b9ffdf37be..408d03ff718 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -47,7 +47,7 @@ use crate::{ }; #[track_caller] -fn check_errors(ra_fixture: &str, expect: Expect) { +fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let db = TestDB::with_files(ra_fixture); let krate = db.fetch_test_crate(); let def_map = db.crate_def_map(krate); @@ -77,7 +77,7 @@ fn check_errors(ra_fixture: &str, expect: Expect) { } #[track_caller] -fn check(ra_fixture: &str, mut expect: Expect) { +fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) { let extra_proc_macros = vec![( r#" #[proc_macro_attribute] @@ -358,6 +358,7 @@ impl ProcMacroExpander for IdentityWhenValidProcMacroExpander { let (parse, _) = syntax_bridge::token_tree_to_syntax_node( subtree, syntax_bridge::TopEntryPoint::MacroItems, + &mut |_| span::Edition::CURRENT, span::Edition::CURRENT, ); if parse.errors().is_empty() { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs index c0178adc9a6..70e3e1ed4e9 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs @@ -181,9 +181,9 @@ fn foo(&self) { self.0. 1; } -fn#0:1@45..47#0# foo#0:1@48..51#0#(#0:1@51..52#0#�:1@52..53#0#self#0:1@53..57#0# )#0:1@57..58#0# {#0:1@59..60#0# - self#0:1@65..69#0# .#0:1@69..70#0#0#0:1@70..71#0#.#0:1@71..72#0#1#0:1@73..74#0#;#0:1@74..75#0# -}#0:1@76..77#0#"#]], +fn#0:1@45..47#2# foo#0:1@48..51#2#(#0:1@51..52#2#�:1@52..53#2#self#0:1@53..57#2# )#0:1@57..58#2# {#0:1@59..60#2# + self#0:1@65..69#2# .#0:1@69..70#2#0#0:1@70..71#2#.#0:1@71..72#2#1#0:1@73..74#2#;#0:1@74..75#2# +}#0:1@76..77#2#"#]], ); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 8beeda82bca..1e4b42dff5f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -74,7 +74,7 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI let proc_macros = if krate.is_proc_macro { db.proc_macros() - .for_crate(def_map.krate, db.syntax_context(tree_id.file_id())) + .for_crate(def_map.krate, db.syntax_context(tree_id.file_id(), krate.edition)) .unwrap_or_default() } else { Default::default() @@ -717,8 +717,8 @@ impl DefCollector<'_> { } } None => { - for (name, def) in root_scope.macros() { - self.def_map.macro_use_prelude.insert(name.clone(), (def, extern_crate)); + for (name, it) in root_scope.macros() { + self.def_map.macro_use_prelude.insert(name.clone(), (it.def, extern_crate)); } } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs index 32c158415ba..318aee04f7b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs @@ -11,19 +11,19 @@ use triomphe::Arc; use crate::{db::DefDatabase, nameres::DefMap, test_db::TestDB}; -fn compute_crate_def_map(ra_fixture: &str) -> Arc<DefMap> { +fn compute_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> Arc<DefMap> { let db = TestDB::with_files(ra_fixture); let krate = db.fetch_test_crate(); db.crate_def_map(krate) } -fn render_crate_def_map(ra_fixture: &str) -> String { +fn render_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { let db = TestDB::with_files(ra_fixture); let krate = db.fetch_test_crate(); db.crate_def_map(krate).dump(&db) } -fn check(ra_fixture: &str, expect: Expect) { +fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let actual = render_crate_def_map(ra_fixture); expect.assert_eq(&actual); } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs index 82da57a9bb2..0b9b6da8d51 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs @@ -166,6 +166,17 @@ impl Resolver { db: &dyn DefDatabase, path: &Path, ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> { + self.resolve_path_in_type_ns_with_prefix_info(db, path).map( + |(resolution, remaining_segments, import, _)| (resolution, remaining_segments, import), + ) + } + + pub fn resolve_path_in_type_ns_with_prefix_info( + &self, + db: &dyn DefDatabase, + path: &Path, + ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)> + { let path = match path { Path::BarePath(mod_path) => mod_path, Path::Normal(it) => it.mod_path(), @@ -181,7 +192,12 @@ impl Resolver { | LangItemTarget::ImplDef(_) | LangItemTarget::Static(_) => return None, }; - return Some((type_ns, seg.as_ref().map(|_| 1), None)); + return Some(( + type_ns, + seg.as_ref().map(|_| 1), + None, + ResolvePathResultPrefixInfo::default(), + )); } }; let first_name = path.segments().first()?; @@ -197,17 +213,32 @@ impl Resolver { Scope::ExprScope(_) | Scope::MacroDefScope(_) => continue, Scope::GenericParams { params, def } => { if let Some(id) = params.find_type_by_name(first_name, *def) { - return Some((TypeNs::GenericParam(id), remaining_idx(), None)); + return Some(( + TypeNs::GenericParam(id), + remaining_idx(), + None, + ResolvePathResultPrefixInfo::default(), + )); } } &Scope::ImplDefScope(impl_) => { if *first_name == sym::Self_.clone() { - return Some((TypeNs::SelfType(impl_), remaining_idx(), None)); + return Some(( + TypeNs::SelfType(impl_), + remaining_idx(), + None, + ResolvePathResultPrefixInfo::default(), + )); } } &Scope::AdtScope(adt) => { if *first_name == sym::Self_.clone() { - return Some((TypeNs::AdtSelfType(adt), remaining_idx(), None)); + return Some(( + TypeNs::AdtSelfType(adt), + remaining_idx(), + None, + ResolvePathResultPrefixInfo::default(), + )); } } Scope::BlockScope(m) => { @@ -220,18 +251,6 @@ impl Resolver { self.module_scope.resolve_path_in_type_ns(db, path) } - pub fn resolve_path_in_type_ns_fully_with_imports( - &self, - db: &dyn DefDatabase, - path: &Path, - ) -> Option<(TypeNs, Option<ImportOrExternCrate>)> { - let (res, unresolved, imp) = self.resolve_path_in_type_ns(db, path)?; - if unresolved.is_some() { - return None; - } - Some((res, imp)) - } - pub fn resolve_path_in_type_ns_fully( &self, db: &dyn DefDatabase, @@ -324,7 +343,7 @@ impl Resolver { if n_segments <= 1 { let mut hygiene_info = if !hygiene_id.is_root() { - let ctx = db.lookup_intern_syntax_context(hygiene_id.0); + let ctx = hygiene_id.lookup(db); ctx.outer_expn.map(|expansion| { let expansion = db.lookup_intern_macro_call(expansion); (ctx.parent, expansion.def) @@ -986,11 +1005,12 @@ impl ModuleItemMap { &self, db: &dyn DefDatabase, path: &ModPath, - ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>)> { - let (module_def, idx, _) = + ) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)> + { + let (module_def, idx, prefix_info) = self.def_map.resolve_path_locally(db, self.module_id, path, BuiltinShadowMode::Other); let (res, import) = to_type_ns(module_def)?; - Some((res, idx, import)) + Some((res, idx, import, prefix_info)) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 4edb6835922..c4473e454a1 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -240,12 +240,12 @@ impl Visibility { if a_ancestors.any(|m| m == mod_b.local_id) { // B is above A - return Some(Visibility::Module(mod_a, expl_b)); + return Some(Visibility::Module(mod_a, expl_a)); } if b_ancestors.any(|m| m == mod_a.local_id) { // A is above B - return Some(Visibility::Module(mod_b, expl_a)); + return Some(Visibility::Module(mod_b, expl_b)); } None diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs index 4510a593af4..28b68121394 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs @@ -4,7 +4,7 @@ use intern::sym; use itertools::{izip, Itertools}; use parser::SyntaxKind; use rustc_hash::FxHashSet; -use span::{MacroCallId, Span, SyntaxContextId}; +use span::{Edition, MacroCallId, Span, SyntaxContextId}; use stdx::never; use syntax_bridge::DocCommentDesugarMode; use tracing::debug; @@ -33,7 +33,7 @@ macro_rules! register_builtin { } impl BuiltinDeriveExpander { - pub fn expander(&self) -> fn(Span, &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { + pub fn expander(&self) -> fn(&dyn ExpandDatabase, Span, &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { match *self { $( BuiltinDeriveExpander::$trait => $expand, )* } @@ -58,8 +58,8 @@ impl BuiltinDeriveExpander { tt: &tt::TopSubtree, span: Span, ) -> ExpandResult<tt::TopSubtree> { - let span = span_with_def_site_ctxt(db, span, id); - self.expander()(span, tt) + let span = span_with_def_site_ctxt(db, span, id, Edition::CURRENT); + self.expander()(db, span, tt) } } @@ -226,8 +226,12 @@ struct AdtParam { } // FIXME: This whole thing needs a refactor. Each derive requires its special values, and the result is a mess. -fn parse_adt(tt: &tt::TopSubtree, call_site: Span) -> Result<BasicAdtInfo, ExpandError> { - let (adt, tm) = to_adt_syntax(tt, call_site)?; +fn parse_adt( + db: &dyn ExpandDatabase, + tt: &tt::TopSubtree, + call_site: Span, +) -> Result<BasicAdtInfo, ExpandError> { + let (adt, tm) = to_adt_syntax(db, tt, call_site)?; parse_adt_from_syntax(&adt, &tm, call_site) } @@ -382,12 +386,14 @@ fn parse_adt_from_syntax( } fn to_adt_syntax( + db: &dyn ExpandDatabase, tt: &tt::TopSubtree, call_site: Span, ) -> Result<(ast::Adt, span::SpanMap<SyntaxContextId>), ExpandError> { - let (parsed, tm) = syntax_bridge::token_tree_to_syntax_node( + let (parsed, tm) = crate::db::token_tree_to_syntax_node( + db, tt, - syntax_bridge::TopEntryPoint::MacroItems, + crate::ExpandTo::Items, parser::Edition::CURRENT_FIXME, ); let macro_items = ast::MacroItems::cast(parsed.syntax_node()) @@ -446,12 +452,13 @@ fn name_to_token( /// where B1, ..., BN are the bounds given by `bounds_paths`. Z is a phantom type, and /// therefore does not get bound by the derived trait. fn expand_simple_derive( + db: &dyn ExpandDatabase, invoc_span: Span, tt: &tt::TopSubtree, trait_path: tt::TopSubtree, make_trait_body: impl FnOnce(&BasicAdtInfo) -> tt::TopSubtree, ) -> ExpandResult<tt::TopSubtree> { - let info = match parse_adt(tt, invoc_span) { + let info = match parse_adt(db, tt, invoc_span) { Ok(info) => info, Err(e) => { return ExpandResult::new( @@ -520,14 +527,22 @@ fn expand_simple_derive_with_parsed( } } -fn copy_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { +fn copy_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { let krate = dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::marker::Copy }, |_| quote! {span =>}) + expand_simple_derive(db, span, tt, quote! {span => #krate::marker::Copy }, |_| quote! {span =>}) } -fn clone_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { +fn clone_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { let krate = dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::clone::Clone }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::clone::Clone }, |adt| { if matches!(adt.shape, AdtShape::Union) { let star = tt::Punct { char: '*', spacing: ::tt::Spacing::Alone, span }; return quote! {span => @@ -576,9 +591,13 @@ fn and_and(span: Span) -> tt::TopSubtree { quote! {span => #and& } } -fn default_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { +fn default_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::default::Default }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::default::Default }, |adt| { let body = match &adt.shape { AdtShape::Struct(fields) => { let name = &adt.name; @@ -615,9 +634,13 @@ fn default_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtre }) } -fn debug_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { +fn debug_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::fmt::Debug }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::fmt::Debug }, |adt| { let for_variant = |name: String, v: &VariantShape| match v { VariantShape::Struct(fields) => { let for_fields = fields.iter().map(|it| { @@ -687,9 +710,13 @@ fn debug_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> }) } -fn hash_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { +fn hash_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::hash::Hash }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::hash::Hash }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here return quote! {span =>}; @@ -734,14 +761,22 @@ fn hash_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> }) } -fn eq_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { +fn eq_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { let krate = dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>}) + expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Eq }, |_| quote! {span =>}) } -fn partial_eq_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { +fn partial_eq_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { let krate = dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::cmp::PartialEq }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialEq }, |adt| { if matches!(adt.shape, AdtShape::Union) { // FIXME: Return expand error here return quote! {span =>}; @@ -811,9 +846,13 @@ fn self_and_other_patterns( (self_patterns, other_patterns) } -fn ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { +fn ord_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::cmp::Ord }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::Ord }, |adt| { fn compare( krate: &tt::Ident, left: tt::TopSubtree, @@ -869,9 +908,13 @@ fn ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { }) } -fn partial_ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { +fn partial_ord_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { let krate = &dollar_crate(span); - expand_simple_derive(span, tt, quote! {span => #krate::cmp::PartialOrd }, |adt| { + expand_simple_derive(db, span, tt, quote! {span => #krate::cmp::PartialOrd }, |adt| { fn compare( krate: &tt::Ident, left: tt::TopSubtree, @@ -932,8 +975,12 @@ fn partial_ord_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSu }) } -fn coerce_pointee_expand(span: Span, tt: &tt::TopSubtree) -> ExpandResult<tt::TopSubtree> { - let (adt, _span_map) = match to_adt_syntax(tt, span) { +fn coerce_pointee_expand( + db: &dyn ExpandDatabase, + span: Span, + tt: &tt::TopSubtree, +) -> ExpandResult<tt::TopSubtree> { + let (adt, _span_map) = match to_adt_syntax(db, tt, span) { Ok(it) => it, Err(err) => { return ExpandResult::new(tt::TopSubtree::empty(tt::DelimSpan::from_single(span)), err); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs index 5b06de98757..310ddaaf9e9 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs @@ -69,7 +69,7 @@ impl BuiltinFnLikeExpander { tt: &tt::TopSubtree, span: Span, ) -> ExpandResult<tt::TopSubtree> { - let span = span_with_def_site_ctxt(db, span, id); + let span = span_with_def_site_ctxt(db, span, id, Edition::CURRENT); self.expander()(db, id, tt, span) } @@ -86,7 +86,7 @@ impl EagerExpander { tt: &tt::TopSubtree, span: Span, ) -> ExpandResult<tt::TopSubtree> { - let span = span_with_def_site_ctxt(db, span, id); + let span = span_with_def_site_ctxt(db, span, id, Edition::CURRENT); self.expander()(db, id, tt, span) } @@ -221,7 +221,7 @@ fn assert_expand( tt: &tt::TopSubtree, span: Span, ) -> ExpandResult<tt::TopSubtree> { - let call_site_span = span_with_call_site_ctxt(db, span, id); + let call_site_span = span_with_call_site_ctxt(db, span, id, Edition::CURRENT); let mut iter = tt.iter(); @@ -342,7 +342,7 @@ fn panic_expand( span: Span, ) -> ExpandResult<tt::TopSubtree> { let dollar_crate = dollar_crate(span); - let call_site_span = span_with_call_site_ctxt(db, span, id); + let call_site_span = span_with_call_site_ctxt(db, span, id, Edition::CURRENT); let mac = if use_panic_2021(db, call_site_span) { sym::panic_2021.clone() @@ -373,7 +373,7 @@ fn unreachable_expand( span: Span, ) -> ExpandResult<tt::TopSubtree> { let dollar_crate = dollar_crate(span); - let call_site_span = span_with_call_site_ctxt(db, span, id); + let call_site_span = span_with_call_site_ctxt(db, span, id, Edition::CURRENT); let mac = if use_panic_2021(db, call_site_span) { sym::unreachable_2021.clone() diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs index 6c1abc26203..9b637fc7684 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs @@ -102,6 +102,7 @@ macro_rules! quote_impl__ { ($span:ident $builder:ident # ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '#')}; ($span:ident $builder:ident $ ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '$')}; ($span:ident $builder:ident * ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '*')}; + ($span:ident $builder:ident = ) => {$crate::builtin::quote::__quote!(@PUNCT($span $builder) '=')}; ($span:ident $builder:ident $first:tt $($tail:tt)+ ) => {{ $crate::builtin::quote::__quote!($span $builder $first); @@ -225,7 +226,7 @@ mod tests { use ::tt::IdentIsRaw; use expect_test::expect; use intern::Symbol; - use span::{SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; + use span::{Edition, SpanAnchor, SyntaxContextId, ROOT_ERASED_FILE_AST_ID}; use syntax::{TextRange, TextSize}; use super::quote; @@ -239,7 +240,7 @@ mod tests { ), ast_id: ROOT_ERASED_FILE_AST_ID, }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }; #[test] @@ -276,8 +277,8 @@ mod tests { assert_eq!(quoted.to_string(), "hello"); let t = format!("{quoted:#?}"); expect![[r#" - SUBTREE $$ 937550:0@0..0#0 937550:0@0..0#0 - IDENT hello 937550:0@0..0#0"#]] + SUBTREE $$ 937550:0@0..0#2 937550:0@0..0#2 + IDENT hello 937550:0@0..0#2"#]] .assert_eq(&t); } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index f4e80ef9e26..b7804f888ae 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -5,7 +5,7 @@ use either::Either; use limit::Limit; use mbe::MatchedArmIndex; use rustc_hash::FxHashSet; -use span::{AstIdMap, EditionedFileId, Span, SyntaxContextData, SyntaxContextId}; +use span::{AstIdMap, Edition, EditionedFileId, Span, SyntaxContextData, SyntaxContextId}; use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T}; use syntax_bridge::{syntax_node_to_token_tree, DocCommentDesugarMode}; use triomphe::Arc; @@ -136,12 +136,12 @@ pub trait ExpandDatabase: SourceDatabase { macro_call: MacroCallId, ) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>; #[ra_salsa::transparent] - fn syntax_context(&self, file: HirFileId) -> SyntaxContextId; + fn syntax_context(&self, file: HirFileId, edition: Edition) -> SyntaxContextId; } -fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId) -> SyntaxContextId { +fn syntax_context(db: &dyn ExpandDatabase, file: HirFileId, edition: Edition) -> SyntaxContextId { match file.repr() { - HirFileIdRepr::FileId(_) => SyntaxContextId::ROOT, + HirFileIdRepr::FileId(_) => SyntaxContextId::root(edition), HirFileIdRepr::MacroFile(m) => { db.macro_arg_considering_derives(m.macro_call_id, &m.macro_call_id.lookup(db).kind) .2 @@ -273,9 +273,9 @@ pub fn expand_speculative( loc.krate, &tt, attr_arg.as_ref(), - span_with_def_site_ctxt(db, span, actual_macro_call), - span_with_call_site_ctxt(db, span, actual_macro_call), - span_with_mixed_site_ctxt(db, span, actual_macro_call), + span_with_def_site_ctxt(db, span, actual_macro_call, loc.def.edition), + span_with_call_site_ctxt(db, span, actual_macro_call, loc.def.edition), + span_with_mixed_site_ctxt(db, span, actual_macro_call, loc.def.edition), ) } MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => { @@ -300,7 +300,7 @@ pub fn expand_speculative( fixup::reverse_fixups(&mut speculative_expansion.value, &undo_info); let (node, rev_tmap) = - token_tree_to_syntax_node(&speculative_expansion.value, expand_to, loc.def.edition); + token_tree_to_syntax_node(db, &speculative_expansion.value, expand_to, loc.def.edition); let syntax_node = node.syntax_node(); let token = rev_tmap @@ -346,6 +346,7 @@ fn parse_macro_expansion( macro_expand(db, macro_file.macro_call_id, loc); let (parse, mut rev_token_map) = token_tree_to_syntax_node( + db, match &tt { CowArc::Arc(it) => it, CowArc::Owned(it) => it, @@ -699,9 +700,9 @@ fn expand_proc_macro( loc.krate, ¯o_arg, attr_arg, - span_with_def_site_ctxt(db, span, id), - span_with_call_site_ctxt(db, span, id), - span_with_mixed_site_ctxt(db, span, id), + span_with_def_site_ctxt(db, span, id, loc.def.edition), + span_with_call_site_ctxt(db, span, id, loc.def.edition), + span_with_mixed_site_ctxt(db, span, id, loc.def.edition), ) }; @@ -715,7 +716,8 @@ fn expand_proc_macro( ExpandResult { value: Arc::new(tt), err } } -fn token_tree_to_syntax_node( +pub(crate) fn token_tree_to_syntax_node( + db: &dyn ExpandDatabase, tt: &tt::TopSubtree, expand_to: ExpandTo, edition: parser::Edition, @@ -727,7 +729,12 @@ fn token_tree_to_syntax_node( ExpandTo::Type => syntax_bridge::TopEntryPoint::Type, ExpandTo::Expr => syntax_bridge::TopEntryPoint::Expr, }; - syntax_bridge::token_tree_to_syntax_node(tt, entry_point, edition) + syntax_bridge::token_tree_to_syntax_node( + tt, + entry_point, + &mut |ctx| ctx.lookup(db).edition, + edition, + ) } fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> { @@ -751,5 +758,7 @@ fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> { } fn setup_syntax_context_root(db: &dyn ExpandDatabase) { - db.intern_syntax_context(SyntaxContextData::root()); + for edition in Edition::iter() { + db.intern_syntax_context(SyntaxContextData::root(edition)); + } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs index d1c39f32ca3..fef77acb7bb 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs @@ -2,7 +2,7 @@ use base_db::CrateId; use intern::sym; -use span::{Edition, MacroCallId, Span, SyntaxContextId}; +use span::{Edition, HirFileIdRepr, MacroCallId, Span, SyntaxContextId}; use stdx::TupleExt; use syntax::{ast, AstNode}; use syntax_bridge::DocCommentDesugarMode; @@ -20,6 +20,7 @@ use crate::{ pub struct DeclarativeMacroExpander { pub mac: mbe::DeclarativeMacro, pub transparency: Transparency, + edition: Edition, } impl DeclarativeMacroExpander { @@ -40,7 +41,7 @@ impl DeclarativeMacroExpander { .mac .expand( &tt, - |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency), + |s| s.ctx = apply_mark(db, s.ctx, call_id, self.transparency, self.edition), span, loc.def.edition, ) @@ -159,6 +160,10 @@ impl DeclarativeMacroExpander { transparency(¯o_def).unwrap_or(Transparency::Opaque), ), }; - Arc::new(DeclarativeMacroExpander { mac, transparency }) + let edition = ctx_edition(match id.file_id.repr() { + HirFileIdRepr::MacroFile(macro_file) => macro_file.macro_call_id.lookup(db).ctxt, + HirFileIdRepr::FileId(file) => SyntaxContextId::root(file.edition()), + }); + Arc::new(DeclarativeMacroExpander { mac, transparency, edition }) } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index 8c04d054029..13ddb0d4acc 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -380,14 +380,14 @@ impl InFile<TextRange> { ) -> (FileRange, SyntaxContextId) { match self.file_id.repr() { HirFileIdRepr::FileId(file_id) => { - (FileRange { file_id, range: self.value }, SyntaxContextId::ROOT) + (FileRange { file_id, range: self.value }, SyntaxContextId::root(file_id.edition())) } HirFileIdRepr::MacroFile(mac_file) => { match map_node_range_up(db, &db.expansion_span_map(mac_file), self.value) { Some(it) => it, None => { let loc = db.lookup_intern_macro_call(mac_file.macro_call_id); - (loc.kind.original_call_range(db), SyntaxContextId::ROOT) + (loc.kind.original_call_range(db), SyntaxContextId::root(loc.def.edition)) } } } @@ -432,9 +432,10 @@ impl InFile<TextRange> { db: &dyn db::ExpandDatabase, ) -> Option<(FileRange, SyntaxContextId)> { match self.file_id.repr() { - HirFileIdRepr::FileId(file_id) => { - Some((FileRange { file_id, range: self.value }, SyntaxContextId::ROOT)) - } + HirFileIdRepr::FileId(file_id) => Some(( + FileRange { file_id, range: self.value }, + SyntaxContextId::root(file_id.edition()), + )), HirFileIdRepr::MacroFile(mac_file) => { map_node_range_up(db, &db.expansion_span_map(mac_file), self.value) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 3d2d52a0afe..eb430177390 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -380,7 +380,7 @@ pub(crate) fn reverse_fixups(tt: &mut TopSubtree, undo_info: &SyntaxFixupUndoInf let span = |file_id| Span { range: TextRange::empty(TextSize::new(0)), anchor: SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::Edition2015), }; delimiter.open = span(delimiter.open.anchor.file_id); delimiter.close = span(delimiter.close.anchor.file_id); @@ -441,8 +441,8 @@ fn transform_tt<'a, 'b>( }; let len_diff = replacement.len() as i64 - old_len as i64; tt.splice(i..i + old_len, replacement.flat_tokens().iter().cloned()); - // `+1` for the loop. - i = i.checked_add_signed(len_diff as isize + 1).unwrap(); + // Skip the newly inserted replacement, we don't want to visit it. + i += replacement.len(); for &subtree_idx in &subtrees_stack { let tt::TokenTree::Subtree(subtree) = &mut tt[subtree_idx] else { @@ -532,7 +532,7 @@ mod tests { } #[track_caller] - fn check(ra_fixture: &str, mut expect: Expect) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) { let parsed = syntax::SourceFile::parse(ra_fixture, span::Edition::CURRENT); let span_map = SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(EditionedFileId::new( FileId::from_raw(0), @@ -562,6 +562,7 @@ mod tests { let (parse, _) = syntax_bridge::token_tree_to_syntax_node( &tt, syntax_bridge::TopEntryPoint::MacroItems, + &mut |_| parser::Edition::CURRENT, parser::Edition::CURRENT, ); assert!( diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index f48de807c28..fe05af0ac9d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -24,26 +24,37 @@ use std::iter; -use span::{MacroCallId, Span, SyntaxContextData, SyntaxContextId}; +use span::{Edition, MacroCallId, Span, SyntaxContextData, SyntaxContextId}; use crate::db::{ExpandDatabase, InternSyntaxContextQuery}; pub use span::Transparency; -pub fn span_with_def_site_ctxt(db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId) -> Span { - span_with_ctxt_from_mark(db, span, expn_id, Transparency::Opaque) +pub fn span_with_def_site_ctxt( + db: &dyn ExpandDatabase, + span: Span, + expn_id: MacroCallId, + edition: Edition, +) -> Span { + span_with_ctxt_from_mark(db, span, expn_id, Transparency::Opaque, edition) } -pub fn span_with_call_site_ctxt(db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId) -> Span { - span_with_ctxt_from_mark(db, span, expn_id, Transparency::Transparent) +pub fn span_with_call_site_ctxt( + db: &dyn ExpandDatabase, + span: Span, + expn_id: MacroCallId, + edition: Edition, +) -> Span { + span_with_ctxt_from_mark(db, span, expn_id, Transparency::Transparent, edition) } pub fn span_with_mixed_site_ctxt( db: &dyn ExpandDatabase, span: Span, expn_id: MacroCallId, + edition: Edition, ) -> Span { - span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiTransparent) + span_with_ctxt_from_mark(db, span, expn_id, Transparency::SemiTransparent, edition) } fn span_with_ctxt_from_mark( @@ -51,8 +62,12 @@ fn span_with_ctxt_from_mark( span: Span, expn_id: MacroCallId, transparency: Transparency, + edition: Edition, ) -> Span { - Span { ctx: apply_mark(db, SyntaxContextId::ROOT, expn_id, transparency), ..span } + Span { + ctx: apply_mark(db, SyntaxContextId::root(edition), expn_id, transparency, edition), + ..span + } } pub(super) fn apply_mark( @@ -60,9 +75,10 @@ pub(super) fn apply_mark( ctxt: SyntaxContextId, call_id: MacroCallId, transparency: Transparency, + edition: Edition, ) -> SyntaxContextId { if transparency == Transparency::Opaque { - return apply_mark_internal(db, ctxt, call_id, transparency); + return apply_mark_internal(db, ctxt, call_id, transparency, edition); } let call_site_ctxt = db.lookup_intern_macro_call(call_id).ctxt; @@ -73,7 +89,7 @@ pub(super) fn apply_mark( }; if call_site_ctxt.is_root() { - return apply_mark_internal(db, ctxt, call_id, transparency); + return apply_mark_internal(db, ctxt, call_id, transparency, edition); } // Otherwise, `expn_id` is a macros 1.0 definition and the call site is in a @@ -86,9 +102,9 @@ pub(super) fn apply_mark( // // See the example at `test/ui/hygiene/legacy_interaction.rs`. for (call_id, transparency) in ctxt.marks(db) { - call_site_ctxt = apply_mark_internal(db, call_site_ctxt, call_id, transparency); + call_site_ctxt = apply_mark_internal(db, call_site_ctxt, call_id, transparency, edition); } - apply_mark_internal(db, call_site_ctxt, call_id, transparency) + apply_mark_internal(db, call_site_ctxt, call_id, transparency, edition) } fn apply_mark_internal( @@ -96,6 +112,7 @@ fn apply_mark_internal( ctxt: SyntaxContextId, call_id: MacroCallId, transparency: Transparency, + edition: Edition, ) -> SyntaxContextId { use base_db::ra_salsa; @@ -108,13 +125,14 @@ fn apply_mark_internal( if transparency >= Transparency::Opaque { let parent = opaque; opaque = ra_salsa::plumbing::get_query_table::<InternSyntaxContextQuery>(db).get_or_insert( - (parent, call_id, transparency), + (parent, call_id, transparency, edition), |new_opaque| SyntaxContextData { outer_expn: call_id, outer_transparency: transparency, parent, opaque: new_opaque, opaque_and_semitransparent: new_opaque, + edition, }, ); } @@ -123,13 +141,14 @@ fn apply_mark_internal( let parent = opaque_and_semitransparent; opaque_and_semitransparent = ra_salsa::plumbing::get_query_table::<InternSyntaxContextQuery>(db).get_or_insert( - (parent, call_id, transparency), + (parent, call_id, transparency, edition), |new_opaque_and_semitransparent| SyntaxContextData { outer_expn: call_id, outer_transparency: transparency, parent, opaque, opaque_and_semitransparent: new_opaque_and_semitransparent, + edition, }, ); } @@ -141,6 +160,7 @@ fn apply_mark_internal( parent, opaque, opaque_and_semitransparent, + edition, }) } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index a0c4c125db4..2c664029f61 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -188,6 +188,8 @@ impl fmt::Display for RenderedExpandError { impl RenderedExpandError { const GENERAL_KIND: &str = "macro-error"; + const DISABLED: &str = "proc-macro-disabled"; + const ATTR_EXP_DISABLED: &str = "attribute-expansion-disabled"; } impl ExpandErrorKind { @@ -196,12 +198,12 @@ impl ExpandErrorKind { ExpandErrorKind::ProcMacroAttrExpansionDisabled => RenderedExpandError { message: "procedural attribute macro expansion is disabled".to_owned(), error: false, - kind: "proc-macros-disabled", + kind: RenderedExpandError::ATTR_EXP_DISABLED, }, ExpandErrorKind::MacroDisabled => RenderedExpandError { message: "proc-macro is explicitly disabled".to_owned(), error: false, - kind: "proc-macro-disabled", + kind: RenderedExpandError::DISABLED, }, &ExpandErrorKind::MissingProcMacroExpander(def_crate) => { match db.proc_macros().get_error_for_crate(def_crate) { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 7ecf5219873..89eae862bd9 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -273,10 +273,9 @@ fn convert_path( res } } - ast::PathSegmentKind::SelfTypeKw => ModPath::from_segments( - PathKind::Plain, - Some(Name::new_symbol(sym::Self_.clone(), SyntaxContextId::ROOT)), - ), + ast::PathSegmentKind::SelfTypeKw => { + ModPath::from_segments(PathKind::Plain, Some(Name::new_symbol_root(sym::Self_.clone()))) + } ast::PathSegmentKind::CrateKw => ModPath::from_segments(PathKind::Crate, iter::empty()), ast::PathSegmentKind::SelfKw => handle_super_kw(0)?, ast::PathSegmentKind::SuperKw => handle_super_kw(1)?, @@ -399,6 +398,9 @@ macro_rules! __known_path { (core::fmt::Debug) => {}; (std::fmt::format) => {}; (core::ops::Try) => {}; + (core::convert::From) => {}; + (core::convert::TryFrom) => {}; + (core::str::FromStr) => {}; ($path:path) => { compile_error!("Please register your known path in the path module") }; @@ -415,3 +417,14 @@ macro_rules! __path { } pub use crate::__path as path; + +#[macro_export] +macro_rules! __tool_path { + ($start:ident $(:: $seg:ident)*) => ({ + $crate::mod_path::ModPath::from_segments($crate::mod_path::PathKind::Plain, vec![ + $crate::name::Name::new_symbol_root(intern::sym::rust_analyzer.clone()), $crate::name::Name::new_symbol_root(intern::sym::$start.clone()), $($crate::name::Name::new_symbol_root(intern::sym::$seg.clone()),)* + ]) + }); +} + +pub use crate::__tool_path as tool_path; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs index 267d5458333..cc53d2e34aa 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs @@ -11,7 +11,7 @@ use syntax::utils::is_raw_identifier; /// and declarations. In theory, names should also carry hygiene info, but we are /// not there yet! /// -/// Note that the rawness (`r#`) of names does not depend on whether they are written raw. +/// Note that the rawness (`r#`) of names is not preserved. Names are always stored without a `r#` prefix. /// This is because we want to show (in completions etc.) names as raw depending on the needs /// of the current crate, for example if it is edition 2021 complete `gen` even if the defining /// crate is in edition 2024 and wrote `r#gen`, and the opposite holds as well. @@ -77,20 +77,49 @@ impl Name { /// Hopefully, this should allow us to integrate hygiene cleaner in the /// future, and to switch to interned representation of names. fn new_text(text: &str) -> Name { + debug_assert!(!text.starts_with("r#")); Name { symbol: Symbol::intern(text), ctx: () } } - pub fn new(text: &str, ctx: SyntaxContextId) -> Name { + pub fn new(text: &str, mut ctx: SyntaxContextId) -> Name { + // For comparisons etc. we remove the edition, because sometimes we search for some `Name` + // and we don't know which edition it came from. + // Can't do that for all `SyntaxContextId`s because it breaks Salsa. + ctx.remove_root_edition(); _ = ctx; Self::new_text(text) } + pub fn new_root(text: &str) -> Name { + // The edition doesn't matter for hygiene. + Self::new(text.trim_start_matches("r#"), SyntaxContextId::root(Edition::Edition2015)) + } + pub fn new_tuple_field(idx: usize) -> Name { - Name { symbol: Symbol::intern(&idx.to_string()), ctx: () } + let symbol = match idx { + 0 => sym::INTEGER_0.clone(), + 1 => sym::INTEGER_1.clone(), + 2 => sym::INTEGER_2.clone(), + 3 => sym::INTEGER_3.clone(), + 4 => sym::INTEGER_4.clone(), + 5 => sym::INTEGER_5.clone(), + 6 => sym::INTEGER_6.clone(), + 7 => sym::INTEGER_7.clone(), + 8 => sym::INTEGER_8.clone(), + 9 => sym::INTEGER_9.clone(), + 10 => sym::INTEGER_10.clone(), + 11 => sym::INTEGER_11.clone(), + 12 => sym::INTEGER_12.clone(), + 13 => sym::INTEGER_13.clone(), + 14 => sym::INTEGER_14.clone(), + 15 => sym::INTEGER_15.clone(), + _ => Symbol::intern(&idx.to_string()), + }; + Name { symbol, ctx: () } } pub fn new_lifetime(lt: &ast::Lifetime) -> Name { - Name { symbol: Symbol::intern(lt.text().as_str()), ctx: () } + Self::new_text(lt.text().as_str().trim_start_matches("r#")) } /// Resolve a name from the text of token. @@ -133,15 +162,18 @@ impl Name { } /// Returns the text this name represents if it isn't a tuple field. + /// + /// Do not use this for user-facing text, use `display` instead to handle editions properly. pub fn as_str(&self) -> &str { self.symbol.as_str() } + // FIXME: Remove this pub fn unescaped(&self) -> UnescapedName<'_> { UnescapedName(self) } - pub fn is_escaped(&self, edition: Edition) -> bool { + pub fn needs_escape(&self, edition: Edition) -> bool { is_raw_identifier(self.symbol.as_str(), edition) } @@ -164,16 +196,19 @@ impl Name { &self.symbol } - pub const fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self { + pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self { + debug_assert!(!symbol.as_str().starts_with("r#")); _ = ctx; Self { symbol, ctx: () } } // FIXME: This needs to go once we have hygiene - pub const fn new_symbol_root(sym: Symbol) -> Self { + pub fn new_symbol_root(sym: Symbol) -> Self { + debug_assert!(!sym.as_str().starts_with("r#")); Self { symbol: sym, ctx: () } } + // FIXME: Remove this #[inline] pub fn eq_ident(&self, ident: &str) -> bool { self.as_str() == ident.trim_start_matches("r#") diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 9f01f1eb259..c8ff6cba3dd 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -856,7 +856,7 @@ fn impl_def_datum( let associated_ty_value_ids = impl_data .items .iter() - .filter_map(|item| match item { + .filter_map(|(_, item)| match item { AssocItemId::TypeAliasId(type_alias) => Some(*type_alias), _ => None, }) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index 0a8bfaa70f8..2d7d4cacd2c 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -31,7 +31,10 @@ fn simplify(e: ConstEvalError) -> ConstEvalError { } #[track_caller] -fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) { +fn check_fail( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + error: impl FnOnce(ConstEvalError) -> bool, +) { let (db, file_id) = TestDB::with_single_file(ra_fixture); match eval_goal(&db, file_id) { Ok(_) => panic!("Expected fail, but it succeeded"), @@ -42,7 +45,7 @@ fn check_fail(ra_fixture: &str, error: impl FnOnce(ConstEvalError) -> bool) { } #[track_caller] -fn check_number(ra_fixture: &str, answer: i128) { +fn check_number(#[rust_analyzer::rust_fixture] ra_fixture: &str, answer: i128) { check_answer(ra_fixture, |b, _| { assert_eq!( b, @@ -54,7 +57,7 @@ fn check_number(ra_fixture: &str, answer: i128) { } #[track_caller] -fn check_str(ra_fixture: &str, answer: &str) { +fn check_str(#[rust_analyzer::rust_fixture] ra_fixture: &str, answer: &str) { check_answer(ra_fixture, |b, mm| { let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap()); let size = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap()); @@ -71,7 +74,10 @@ fn check_str(ra_fixture: &str, answer: &str) { } #[track_caller] -fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { +fn check_answer( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + check: impl FnOnce(&[u8], &MemoryMap), +) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); let file_id = *file_ids.last().unwrap(); let r = match eval_goal(&db, file_id) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index a4e052a0362..3545bf76776 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -471,10 +471,55 @@ impl HirDisplay for ProjectionTy { if f.should_truncate() { return write!(f, "{TYPE_HINT_TRUNCATION}"); } - let trait_ref = self.trait_ref(f.db); + let self_ty = trait_ref.self_type_parameter(Interner); + + // if we are projection on a type parameter, check if the projection target has bounds + // itself, if so, we render them directly as `impl Bound` instead of the less useful + // `<Param as Trait>::Assoc` + if !f.display_target.is_source_code() { + if let TyKind::Placeholder(idx) = self_ty.kind(Interner) { + let db = f.db; + let id = from_placeholder_idx(db, *idx); + let generics = generics(db.upcast(), id.parent); + + let substs = generics.placeholder_subst(db); + let bounds = db + .generic_predicates(id.parent) + .iter() + .map(|pred| pred.clone().substitute(Interner, &substs)) + .filter(|wc| match wc.skip_binders() { + WhereClause::Implemented(tr) => { + match tr.self_type_parameter(Interner).kind(Interner) { + TyKind::Alias(AliasTy::Projection(proj)) => proj == self, + _ => false, + } + } + WhereClause::TypeOutlives(t) => match t.ty.kind(Interner) { + TyKind::Alias(AliasTy::Projection(proj)) => proj == self, + _ => false, + }, + // We shouldn't be here if these exist + WhereClause::AliasEq(_) => false, + WhereClause::LifetimeOutlives(_) => false, + }) + .collect::<Vec<_>>(); + if !bounds.is_empty() { + return write_bounds_like_dyn_trait_with_prefix( + f, + "impl", + Either::Left( + &TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner), + ), + &bounds, + SizedByDefault::NotSized, + ); + }; + } + } + write!(f, "<")?; - trait_ref.self_type_parameter(Interner).hir_fmt(f)?; + self_ty.hir_fmt(f)?; write!(f, " as ")?; trait_ref.hir_fmt(f)?; write!( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs index 8a56bd28b59..3060b610bb6 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs @@ -26,7 +26,7 @@ enum DynCompatibilityViolationKind { } fn check_dyn_compatibility<'a>( - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, expected: impl IntoIterator<Item = (&'a str, Vec<DynCompatibilityViolationKind>)>, ) { let mut expected: FxHashMap<_, _> = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 66159ddce2b..4d3896660b4 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -25,7 +25,10 @@ fn current_machine_data_layout() -> String { .unwrap() } -fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> { +fn eval_goal( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + minicore: &str, +) -> Result<Arc<Layout>, LayoutError> { let target_data_layout = current_machine_data_layout(); let ra_fixture = format!( "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\n{ra_fixture}", @@ -81,7 +84,10 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro } /// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait` -fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> { +fn eval_expr( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + minicore: &str, +) -> Result<Arc<Layout>, LayoutError> { let target_data_layout = current_machine_data_layout(); let ra_fixture = format!( "//- target_data_layout: {target_data_layout}\n{minicore}//- /main.rs crate:test\nfn main(){{let goal = {{{ra_fixture}}};}}", @@ -114,21 +120,31 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro } #[track_caller] -fn check_size_and_align(ra_fixture: &str, minicore: &str, size: u64, align: u64) { +fn check_size_and_align( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + minicore: &str, + size: u64, + align: u64, +) { let l = eval_goal(ra_fixture, minicore).unwrap(); assert_eq!(l.size.bytes(), size, "size mismatch"); assert_eq!(l.align.abi.bytes(), align, "align mismatch"); } #[track_caller] -fn check_size_and_align_expr(ra_fixture: &str, minicore: &str, size: u64, align: u64) { +fn check_size_and_align_expr( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + minicore: &str, + size: u64, + align: u64, +) { let l = eval_expr(ra_fixture, minicore).unwrap(); assert_eq!(l.size.bytes(), size, "size mismatch"); assert_eq!(l.align.abi.bytes(), align, "align mismatch"); } #[track_caller] -fn check_fail(ra_fixture: &str, e: LayoutError) { +fn check_fail(#[rust_analyzer::rust_fixture] ra_fixture: &str, e: LayoutError) { let r = eval_goal(ra_fixture, ""); assert_eq!(r, Err(e)); } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 24f67fd6602..432b8f4d94e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -761,8 +761,8 @@ impl<'a> TyLoweringContext<'a> { path: &Path, on_diagnostic: &mut dyn FnMut(&mut Self, PathLoweringDiagnostic), ) -> Option<(TypeNs, Option<usize>)> { - let (resolution, remaining_index, _) = - self.resolver.resolve_path_in_type_ns(self.db.upcast(), path)?; + let (resolution, remaining_index, _, prefix_info) = + self.resolver.resolve_path_in_type_ns_with_prefix_info(self.db.upcast(), path)?; let segments = path.segments(); match path { @@ -771,13 +771,12 @@ impl<'a> TyLoweringContext<'a> { _ => return Some((resolution, remaining_index)), }; - let (module_segments, resolved_segment_idx, resolved_segment) = match remaining_index { - None => ( - segments.strip_last(), - segments.len() - 1, - segments.last().expect("resolved path has at least one element"), - ), - Some(i) => (segments.take(i - 1), i - 1, segments.get(i - 1).unwrap()), + let (module_segments, resolved_segment_idx, enum_segment) = match remaining_index { + None if prefix_info.enum_variant => { + (segments.strip_last_two(), segments.len() - 1, Some(segments.len() - 2)) + } + None => (segments.strip_last(), segments.len() - 1, None), + Some(i) => (segments.take(i - 1), i - 1, None), }; for (i, mod_segment) in module_segments.iter().enumerate() { @@ -792,9 +791,23 @@ impl<'a> TyLoweringContext<'a> { } } + if let Some(enum_segment) = enum_segment { + if segments.get(enum_segment).is_some_and(|it| it.args_and_bindings.is_some()) + && segments.get(enum_segment + 1).is_some_and(|it| it.args_and_bindings.is_some()) + { + on_diagnostic( + self, + PathLoweringDiagnostic::GenericArgsProhibited { + segment: (enum_segment + 1) as u32, + reason: GenericArgsProhibitedReason::EnumVariant, + }, + ); + } + } + self.handle_type_ns_resolution( &resolution, - resolved_segment, + segments.get(resolved_segment_idx).expect("should have resolved segment"), resolved_segment_idx, on_diagnostic, ); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index 62b071b2f32..182032f0481 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -746,16 +746,9 @@ fn lookup_impl_assoc_item_for_trait_ref( let table = InferenceTable::new(db, env); let (impl_data, impl_subst) = find_matching_impl(impls, table, trait_ref)?; - let item = impl_data.items.iter().find_map(|&it| match it { - AssocItemId::FunctionId(f) => { - (db.function_data(f).name == *name).then_some(AssocItemId::FunctionId(f)) - } - AssocItemId::ConstId(c) => db - .const_data(c) - .name - .as_ref() - .map(|n| n == name) - .and_then(|result| if result { Some(AssocItemId::ConstId(c)) } else { None }), + let item = impl_data.items.iter().find_map(|(n, it)| match *it { + AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)), + AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)), AssocItemId::TypeAliasId(_) => None, })?; Some((item, impl_subst)) @@ -850,7 +843,7 @@ fn is_inherent_impl_coherent( }; rustc_has_incoherent_inherent_impls && !impl_data.items.is_empty() - && impl_data.items.iter().copied().all(|assoc| match assoc { + && impl_data.items.iter().all(|&(_, assoc)| match assoc { AssocItemId::FunctionId(it) => db.function_data(it).rustc_allow_incoherent_impl, AssocItemId::ConstId(it) => db.const_data(it).rustc_allow_incoherent_impl, AssocItemId::TypeAliasId(it) => db.type_alias_data(it).rustc_allow_incoherent_impl, @@ -1399,7 +1392,7 @@ fn iterate_inherent_methods( callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, ) -> ControlFlow<()> { for &impl_id in impls.for_self_ty(self_ty) { - for &item in table.db.impl_data(impl_id).items.iter() { + for &(ref item_name, item) in table.db.impl_data(impl_id).items.iter() { let visible = match is_valid_impl_method_candidate( table, self_ty, @@ -1408,6 +1401,7 @@ fn iterate_inherent_methods( name, impl_id, item, + item_name, ) { IsValidCandidate::Yes => true, IsValidCandidate::NotVisible => false, @@ -1467,6 +1461,7 @@ fn is_valid_impl_method_candidate( name: Option<&Name>, impl_id: ImplId, item: AssocItemId, + item_name: &Name, ) -> IsValidCandidate { match item { AssocItemId::FunctionId(f) => is_valid_impl_fn_candidate( @@ -1477,11 +1472,12 @@ fn is_valid_impl_method_candidate( receiver_ty, self_ty, visible_from_module, + item_name, ), AssocItemId::ConstId(c) => { let db = table.db; check_that!(receiver_ty.is_none()); - check_that!(name.is_none_or(|n| db.const_data(c).name.as_ref() == Some(n))); + check_that!(name.is_none_or(|n| n == item_name)); if let Some(from_module) = visible_from_module { if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) { @@ -1565,11 +1561,13 @@ fn is_valid_impl_fn_candidate( receiver_ty: Option<&Ty>, self_ty: &Ty, visible_from_module: Option<ModuleId>, + item_name: &Name, ) -> IsValidCandidate { + check_that!(name.is_none_or(|n| n == item_name)); + let db = table.db; let data = db.function_data(fn_id); - check_that!(name.is_none_or(|n| n == &data.name)); if let Some(from_module) = visible_from_module { if !db.function_visibility(fn_id).is_visible_from(db.upcast(), from_module) { cov_mark::hit!(autoderef_candidate_not_visible); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index ce43e90df7d..f1e86daea23 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -37,11 +37,15 @@ fn eval_main(db: &TestDB, file_id: EditionedFileId) -> Result<(String, String), Ok((output.stdout().into_owned(), output.stderr().into_owned())) } -fn check_pass(ra_fixture: &str) { +fn check_pass(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_pass_and_stdio(ra_fixture, "", ""); } -fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr: &str) { +fn check_pass_and_stdio( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expected_stdout: &str, + expected_stderr: &str, +) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); let file_id = *file_ids.last().unwrap(); let x = eval_main(&db, file_id); @@ -73,7 +77,7 @@ fn check_pass_and_stdio(ra_fixture: &str, expected_stdout: &str, expected_stderr } } -fn check_panic(ra_fixture: &str, expected_panic: &str) { +fn check_panic(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_panic: &str) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); let file_id = *file_ids.last().unwrap(); let e = eval_main(&db, file_id).unwrap_err(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs index b7607b5f639..00da9b25176 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs @@ -69,27 +69,32 @@ fn setup_tracing() -> Option<tracing::subscriber::DefaultGuard> { } #[track_caller] -fn check_types(ra_fixture: &str) { +fn check_types(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_impl(ra_fixture, false, true, false) } #[track_caller] -fn check_types_source_code(ra_fixture: &str) { +fn check_types_source_code(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_impl(ra_fixture, false, true, true) } #[track_caller] -fn check_no_mismatches(ra_fixture: &str) { +fn check_no_mismatches(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_impl(ra_fixture, true, false, false) } #[track_caller] -fn check(ra_fixture: &str) { +fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_impl(ra_fixture, false, false, false) } #[track_caller] -fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_source: bool) { +fn check_impl( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + allow_none: bool, + only_types: bool, + display_source: bool, +) { let _tracing = setup_tracing(); let (db, files) = TestDB::with_many_files(ra_fixture); @@ -282,7 +287,7 @@ fn pat_node( }) } -fn infer(ra_fixture: &str) -> String { +fn infer(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { infer_with_mismatches(ra_fixture, false) } @@ -430,7 +435,7 @@ pub(crate) fn visit_module( visit_scope(db, crate_def_map, &crate_def_map[module_id].scope, cb); for impl_id in crate_def_map[module_id].scope.impls() { let impl_data = db.impl_data(impl_id); - for &item in impl_data.items.iter() { + for &(_, item) in impl_data.items.iter() { match item { AssocItemId::FunctionId(it) => { let body = db.body(it.into()); @@ -520,13 +525,13 @@ fn ellipsize(mut text: String, max_len: usize) -> String { text } -fn check_infer(ra_fixture: &str, expect: Expect) { +fn check_infer(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let mut actual = infer(ra_fixture); actual.push('\n'); expect.assert_eq(&actual); } -fn check_infer_with_mismatches(ra_fixture: &str, expect: Expect) { +fn check_infer_with_mismatches(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let mut actual = infer_with_mismatches(ra_fixture, true); actual.push('\n'); expect.assert_eq(&actual); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs index 7de92d6b160..34d299edd1b 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs @@ -14,7 +14,7 @@ use crate::test_db::TestDB; use super::visit_module; -fn check_closure_captures(ra_fixture: &str, expect: Expect) { +fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, file_id) = TestDB::with_single_file(ra_fixture); let module = db.module_for_file(file_id); let def_map = module.def_map(&db); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs index 5f0f341f393..15636604570 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs @@ -3802,3 +3802,15 @@ fn foo() { "#, ); } + +#[test] +fn tool_attr_skip() { + check_no_mismatches( + r#" +#[rust_analyzer::skip] +async fn foo(a: (), b: i32) -> u32 { + 0 + 1 + b() +} + "#, + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs index 30711b16dfb..afd163fbd96 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs @@ -968,7 +968,7 @@ struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V); } #[track_caller] - fn check(ra_fixture: &str, expected: Expect) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: Expect) { // use tracing_subscriber::{layer::SubscriberExt, Layer}; // let my_layer = tracing_subscriber::fmt::layer(); // let _g = tracing::subscriber::set_default(tracing_subscriber::registry().with( diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 6aadc5c4f7e..c68ff706e48 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -20,6 +20,7 @@ itertools.workspace = true smallvec.workspace = true tracing.workspace = true triomphe.workspace = true +indexmap.workspace = true # local deps base-db.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index a23fdf1b393..4351a34e822 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -12,7 +12,6 @@ use hir_def::{ }; use hir_expand::{mod_path::PathKind, name::Name}; use hir_ty::{db::HirDatabase, method_resolution}; -use span::SyntaxContextId; use crate::{ Adt, AsAssocItem, AssocItem, BuiltinType, Const, ConstParam, DocLinkDef, Enum, ExternCrateDecl, @@ -90,6 +89,16 @@ impl HasAttrs for AssocItem { } } +impl HasAttrs for crate::Crate { + fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner { + let def = AttrDefId::ModuleId(self.root_module().id); + AttrsWithOwner::new(db.upcast(), def) + } + fn attr_id(self) -> AttrDefId { + AttrDefId::ModuleId(self.root_module().id) + } +} + /// Resolves the item `link` points to in the scope of `def`. pub fn resolve_doc_path_on( db: &dyn HirDatabase, @@ -328,9 +337,7 @@ fn doc_modpath_from_str(link: &str) -> Option<ModPath> { }; let parts = first_segment.into_iter().chain(parts).map(|segment| match segment.parse() { Ok(idx) => Name::new_tuple_field(idx), - Err(_) => { - Name::new(segment.split_once('<').map_or(segment, |it| it.0), SyntaxContextId::ROOT) - } + Err(_) => Name::new_root(segment.split_once('<').map_or(segment, |it| it.0)), }); Some(ModPath::from_segments(kind, parts)) }; diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index e09ded32fbd..b29c91694d3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -23,10 +23,10 @@ use hir_ty::{ use itertools::Itertools; use crate::{ - Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, - Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module, - SelfParam, Static, Struct, Trait, TraitAlias, TraitRef, TupleField, TyBuilder, Type, TypeAlias, - TypeOrConstParam, TypeParam, Union, Variant, + Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum, + ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, + Macro, Module, SelfParam, Static, Struct, Trait, TraitAlias, TraitRef, TupleField, TyBuilder, + Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, }; impl HirDisplay for Function { @@ -846,14 +846,27 @@ impl HirDisplay for TypeAlias { impl HirDisplay for Module { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - // FIXME: Module doesn't have visibility saved in data. + match self.parent(f.db) { + Some(m) => write_visibility(m.id, self.visibility(f.db), f)?, + None => { + return match self.krate(f.db).display_name(f.db) { + Some(name) => write!(f, "extern crate {name}"), + None => f.write_str("extern crate {unknown}"), + } + } + } match self.name(f.db) { Some(name) => write!(f, "mod {}", name.display(f.db.upcast(), f.edition())), - None if self.is_crate_root() => match self.krate(f.db).display_name(f.db) { - Some(name) => write!(f, "extern crate {name}"), - None => f.write_str("extern crate {unknown}"), - }, - None => f.write_str("mod {unnamed}"), + None => f.write_str("mod {unknown}"), + } + } +} + +impl HirDisplay for Crate { + fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + match self.display_name(f.db) { + Some(name) => write!(f, "extern crate {name}"), + None => f.write_str("extern crate {unknown}"), } } } diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 00b4db54374..db3121d3cd3 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -54,11 +54,11 @@ use hir_def::{ per_ns::PerNs, resolver::{HasResolver, Resolver}, type_ref::TypesSourceMap, - AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, CrateRootModuleId, - DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, - HasModule, ImplId, InTypeConstId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, - MacroExpander, ModuleId, StaticId, StructId, SyntheticSyntax, TraitAliasId, TraitId, TupleId, - TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, + AdtId, AssocItemId, AssocItemLoc, AttrDefId, CallableDefId, ConstId, ConstParamId, + CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId, ExternCrateId, FunctionId, + GenericDefId, GenericParamId, HasModule, ImplId, InTypeConstId, ItemContainerId, + LifetimeParamId, LocalFieldId, Lookup, MacroExpander, MacroId, ModuleId, StaticId, StructId, + SyntheticSyntax, TraitAliasId, TupleId, TypeAliasId, TypeOrConstParamId, TypeParamId, UnionId, }; use hir_expand::{ attrs::collect_attrs, proc_macro::ProcMacroKind, AstId, MacroCallKind, RenderedExpandError, @@ -83,7 +83,7 @@ use itertools::Itertools; use nameres::diagnostics::DefDiagnosticKind; use rustc_hash::FxHashSet; use smallvec::SmallVec; -use span::{Edition, EditionedFileId, FileId, MacroCallId, SyntaxContextId}; +use span::{Edition, EditionedFileId, FileId, MacroCallId}; use stdx::{format_to, impl_from, never}; use syntax::{ ast::{self, HasAttrs as _, HasGenericParams, HasName}, @@ -127,7 +127,7 @@ pub use { ImportPathConfig, // FIXME: This is here since some queries take it as input that are used // outside of hir. - {AdtId, MacroId, ModuleDefId}, + {ModuleDefId, TraitId}, }, hir_expand::{ attrs::{Attr, AttrId}, @@ -775,29 +775,16 @@ impl Module { AssocItemId::ConstId(id) => !db.const_data(id).has_body, AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(), }); - impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().filter_map( - |&item| { - Some(( - item, - match item { - AssocItemId::FunctionId(it) => db.function_data(it).name.clone(), - AssocItemId::ConstId(it) => { - db.const_data(it).name.as_ref()?.clone() - } - AssocItemId::TypeAliasId(it) => db.type_alias_data(it).name.clone(), - }, - )) - }, - )); + impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().cloned()); let redundant = impl_assoc_items_scratch .iter() - .filter(|(id, name)| { + .filter(|(name, id)| { !items.iter().any(|(impl_name, impl_item)| { discriminant(impl_item) == discriminant(id) && impl_name == name }) }) - .map(|(item, name)| (name.clone(), AssocItem::from(*item))); + .map(|(name, item)| (name.clone(), AssocItem::from(*item))); for (name, assoc_item) in redundant { acc.push( TraitImplRedundantAssocItems { @@ -812,7 +799,7 @@ impl Module { let missing: Vec<_> = required_items .filter(|(name, id)| { - !impl_assoc_items_scratch.iter().any(|(impl_item, impl_name)| { + !impl_assoc_items_scratch.iter().any(|(impl_name, impl_item)| { discriminant(impl_item) == discriminant(id) && impl_name == name }) }) @@ -844,7 +831,7 @@ impl Module { source_map, ); - for &item in db.impl_data(impl_def.id).items.iter() { + for &(_, item) in db.impl_data(impl_def.id).items.iter() { AssocItem::from(item).diagnostics(db, acc, style_lints); } } @@ -3000,6 +2987,10 @@ impl Macro { matches!(self.id, MacroId::MacroRulesId(id) if db.macro_rules_data(id).macro_export) } + pub fn is_proc_macro(self) -> bool { + matches!(self.id, MacroId::ProcMacroId(_)) + } + pub fn kind(&self, db: &dyn HirDatabase) -> MacroKind { match self.id { MacroId::Macro2Id(it) => match it.lookup(db.upcast()).expander { @@ -3046,14 +3037,23 @@ impl Macro { MacroId::Macro2Id(it) => { matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInEager(eager) if eager.is_env_or_option_env()) } - MacroId::MacroRulesId(_) | MacroId::ProcMacroId(_) => false, + MacroId::MacroRulesId(it) => { + matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltInEager(eager) if eager.is_env_or_option_env()) + } + MacroId::ProcMacroId(_) => false, } } pub fn is_asm_or_global_asm(&self, db: &dyn HirDatabase) -> bool { - matches!(self.id, MacroId::Macro2Id(it) if { - matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm()) - }) + match self.id { + MacroId::Macro2Id(it) => { + matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm()) + } + MacroId::MacroRulesId(it) => { + matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm()) + } + MacroId::ProcMacroId(_) => false, + } } pub fn is_attr(&self, db: &dyn HirDatabase) -> bool { @@ -3902,6 +3902,10 @@ impl ToolModule { db.crate_def_map(self.krate).registered_tools()[self.idx as usize].clone(), ) } + + pub fn krate(&self) -> Crate { + Crate { id: self.krate } + } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -4290,7 +4294,7 @@ impl Impl { } pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { - db.impl_data(self.id).items.iter().map(|&it| it.into()).collect() + db.impl_data(self.id).items.iter().map(|&(_, it)| it.into()).collect() } pub fn is_negative(self, db: &dyn HirDatabase) -> bool { @@ -4731,6 +4735,14 @@ impl Type { Some((self.derived(ty.clone()), m)) } + pub fn add_reference(&self, mutability: Mutability) -> Type { + let ty_mutability = match mutability { + Mutability::Shared => hir_ty::Mutability::Not, + Mutability::Mut => hir_ty::Mutability::Mut, + }; + self.derived(TyKind::Ref(ty_mutability, error_lifetime(), self.ty.clone()).intern(Interner)) + } + pub fn is_slice(&self) -> bool { matches!(self.ty.kind(Interner), TyKind::Slice(..)) } @@ -4786,9 +4798,9 @@ impl Type { } /// Checks that particular type `ty` implements `std::future::IntoFuture` or - /// `std::future::Future`. + /// `std::future::Future` and returns the `Output` associated type. /// This function is used in `.await` syntax completion. - pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool { + pub fn into_future_output(&self, db: &dyn HirDatabase) -> Option<Type> { let trait_ = db .lang_item(self.env.krate, LangItem::IntoFutureIntoFuture) .and_then(|it| { @@ -4800,16 +4812,18 @@ impl Type { .or_else(|| { let future_trait = db.lang_item(self.env.krate, LangItem::Future)?; future_trait.as_trait() - }); - - let trait_ = match trait_ { - Some(it) => it, - None => return false, - }; + })?; let canonical_ty = Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; - method_resolution::implements_trait(&canonical_ty, db, &self.env, trait_) + if !method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, trait_) { + return None; + } + + let output_assoc_type = db + .trait_data(trait_) + .associated_type_by_name(&Name::new_symbol_root(sym::Output.clone()))?; + self.normalize_trait_assoc_type(db, &[], output_assoc_type.into()) } /// This does **not** resolve `IntoFuture`, only `Future`. @@ -4824,10 +4838,31 @@ impl Type { let iterator_trait = db.lang_item(self.env.krate, LangItem::Iterator)?.as_trait()?; let iterator_item = db .trait_data(iterator_trait) - .associated_type_by_name(&Name::new_symbol(sym::Item.clone(), SyntaxContextId::ROOT))?; + .associated_type_by_name(&Name::new_symbol_root(sym::Item.clone()))?; self.normalize_trait_assoc_type(db, &[], iterator_item.into()) } + /// Resolves the projection `<Self as IntoIterator>::IntoIter` and returns the resulting type + pub fn into_iterator_iter(self, db: &dyn HirDatabase) -> Option<Type> { + let trait_ = db.lang_item(self.env.krate, LangItem::IntoIterIntoIter).and_then(|it| { + let into_iter_fn = it.as_function()?; + let assoc_item = as_assoc_item(db, AssocItem::Function, into_iter_fn)?; + let into_iter_trait = assoc_item.container_or_implemented_trait(db)?; + Some(into_iter_trait.id) + })?; + + let canonical_ty = + Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) }; + if !method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, trait_) { + return None; + } + + let into_iter_assoc_type = db + .trait_data(trait_) + .associated_type_by_name(&Name::new_symbol_root(sym::IntoIter.clone()))?; + self.normalize_trait_assoc_type(db, &[], into_iter_assoc_type.into()) + } + /// Checks that particular type `ty` implements `std::ops::FnOnce`. /// /// This function can be used to check if a particular type is callable, since FnOnce is a @@ -5117,7 +5152,7 @@ impl Type { let impls = db.inherent_impls_in_crate(krate); for impl_def in impls.for_self_ty(&self.ty) { - for &item in db.impl_data(*impl_def).items.iter() { + for &(_, item) in db.impl_data(*impl_def).items.iter() { if callback(item) { return; } @@ -5535,6 +5570,7 @@ impl Type { walk_substs(db, type_, &opaque_ty.substitution, cb); } TyKind::Placeholder(_) => { + cb(type_.derived(ty.clone())); if let Some(bounds) = ty.impl_trait_bounds(db) { walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 34d169cd761..523bc6f10aa 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -39,8 +39,8 @@ use stdx::TupleExt; use syntax::{ algo::skip_trivia_token, ast::{self, HasAttrs as _, HasGenericParams}, - AstNode, AstToken, Direction, SmolStr, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, - TextRange, TextSize, + AstNode, AstToken, Direction, SyntaxKind, SyntaxNode, SyntaxNodePtr, SyntaxToken, TextRange, + TextSize, }; use triomphe::Arc; @@ -136,8 +136,6 @@ pub struct Semantics<'db, DB> { pub struct SemanticsImpl<'db> { pub db: &'db dyn HirDatabase, s2d_cache: RefCell<SourceToDefCache>, - /// Rootnode to HirFileId cache - root_to_file_cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>, /// MacroCall to its expansion's MacroFileId cache macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroFileId>>, } @@ -304,12 +302,7 @@ impl<DB: HirDatabase> Semantics<'_, DB> { impl<'db> SemanticsImpl<'db> { fn new(db: &'db dyn HirDatabase) -> Self { - SemanticsImpl { - db, - s2d_cache: Default::default(), - root_to_file_cache: Default::default(), - macro_call_cache: Default::default(), - } + SemanticsImpl { db, s2d_cache: Default::default(), macro_call_cache: Default::default() } } pub fn parse(&self, file_id: EditionedFileId) -> ast::SourceFile { @@ -483,7 +476,7 @@ impl<'db> SemanticsImpl<'db> { Some( calls .into_iter() - .map(|call| macro_call_to_macro_id(self, ctx, call?).map(|id| Macro { id })) + .map(|call| macro_call_to_macro_id(ctx, call?).map(|id| Macro { id })) .collect(), ) }) @@ -962,7 +955,7 @@ impl<'db> SemanticsImpl<'db> { let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| { Some( ctx.cache - .get_or_insert_expansion(self, macro_file) + .get_or_insert_expansion(ctx.db, macro_file) .map_range_down(span)? .map(SmallVec::<[_; 2]>::from_iter), ) @@ -986,7 +979,10 @@ impl<'db> SemanticsImpl<'db> { process_expansion_for_token(&mut stack, include)?; } None => { - stack.push((file_id.into(), smallvec![(token, SyntaxContextId::ROOT)])); + stack.push(( + file_id.into(), + smallvec![(token, SyntaxContextId::root(file_id.edition()))], + )); } } @@ -1284,7 +1280,7 @@ impl<'db> SemanticsImpl<'db> { let macro_file = file_id.macro_file()?; self.with_ctx(|ctx| { - let expansion_info = ctx.cache.get_or_insert_expansion(self, macro_file); + let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); expansion_info.arg().map(|node| node?.parent()).transpose() }) } @@ -1315,8 +1311,8 @@ impl<'db> SemanticsImpl<'db> { } pub fn resolve_label(&self, label: &ast::Lifetime) -> Option<Label> { - let (parent, label_id) = self - .with_ctx(|ctx| ctx.label_ref_to_def(self.wrap_node_infile(label.clone()).as_ref()))?; + let src = self.wrap_node_infile(label.clone()); + let (parent, label_id) = self.with_ctx(|ctx| ctx.label_ref_to_def(src.as_ref()))?; Some(Label { parent, label_id }) } @@ -1443,6 +1439,10 @@ impl<'db> SemanticsImpl<'db> { self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call) } + pub fn resolve_known_blanket_dual_impls(&self, call: &ast::MethodCallExpr) -> Option<Function> { + self.analyze(call.syntax())?.resolve_known_blanket_dual_impls(self.db, call) + } + fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> { self.analyze(range_pat.syntax())?.resolve_range_pat(self.db, range_pat) } @@ -1516,7 +1516,7 @@ impl<'db> SemanticsImpl<'db> { let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call); self.with_ctx(|ctx| { ctx.macro_call_to_macro_call(macro_call) - .and_then(|call| macro_call_to_macro_id(self, ctx, call)) + .and_then(|call| macro_call_to_macro_id(ctx, call)) .map(Into::into) }) .or_else(|| { @@ -1558,7 +1558,7 @@ impl<'db> SemanticsImpl<'db> { let item_in_file = self.wrap_node_infile(item.clone()); let id = self.with_ctx(|ctx| { let macro_call_id = ctx.item_to_macro_call(item_in_file.as_ref())?; - macro_call_to_macro_id(self, ctx, macro_call_id) + macro_call_to_macro_id(ctx, macro_call_id) })?; Some(Macro { id }) } @@ -1591,14 +1591,11 @@ impl<'db> SemanticsImpl<'db> { pub fn resolve_mod_path_relative( &self, to: Module, - segments: impl IntoIterator<Item = SmolStr>, + segments: impl IntoIterator<Item = Name>, ) -> Option<impl Iterator<Item = ItemInNs>> { let items = to.id.resolver(self.db.upcast()).resolve_module_path_in_items( self.db.upcast(), - &ModPath::from_segments( - hir_def::path::PathKind::Plain, - segments.into_iter().map(|it| Name::new(&it, SyntaxContextId::ROOT)), - ), + &ModPath::from_segments(hir_def::path::PathKind::Plain, segments), ); Some(items.iter_items().map(|(item, _)| item.into())) } @@ -1722,10 +1719,11 @@ impl<'db> SemanticsImpl<'db> { } fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) { - assert!(root_node.parent().is_none()); - let mut cache = self.root_to_file_cache.borrow_mut(); - let prev = cache.insert(root_node, file_id); - assert!(prev.is_none() || prev == Some(file_id)); + SourceToDefCache::cache( + &mut self.s2d_cache.borrow_mut().root_to_file_cache, + root_node, + file_id, + ); } pub fn assert_contains_node(&self, node: &SyntaxNode) { @@ -1733,8 +1731,8 @@ impl<'db> SemanticsImpl<'db> { } fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> { - let cache = self.root_to_file_cache.borrow(); - cache.get(root_node).copied() + let cache = self.s2d_cache.borrow(); + cache.root_to_file_cache.get(root_node).copied() } fn wrap_node_infile<N: AstNode>(&self, node: N) -> InFile<N> { @@ -1753,13 +1751,14 @@ impl<'db> SemanticsImpl<'db> { let file_id = self.lookup(&root_node).unwrap_or_else(|| { panic!( "\n\nFailed to lookup {:?} in this Semantics.\n\ - Make sure to use only query nodes, derived from this instance of Semantics.\n\ + Make sure to only query nodes derived from this instance of Semantics.\n\ root node: {:?}\n\ known nodes: {}\n\n", node, root_node, - self.root_to_file_cache + self.s2d_cache .borrow() + .root_to_file_cache .keys() .map(|it| format!("{it:?}")) .collect::<Vec<_>>() @@ -1906,7 +1905,6 @@ impl<'db> SemanticsImpl<'db> { } fn macro_call_to_macro_id( - sema: &SemanticsImpl<'_>, ctx: &mut SourceToDefCtx<'_, '_>, macro_call_id: MacroCallId, ) -> Option<MacroId> { @@ -1922,7 +1920,7 @@ fn macro_call_to_macro_id( it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) } HirFileIdRepr::MacroFile(macro_file) => { - let expansion_info = ctx.cache.get_or_insert_expansion(sema, macro_file); + let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); it.to_ptr(db).to_node(&expansion_info.expanded().value) } }; @@ -1934,7 +1932,7 @@ fn macro_call_to_macro_id( it.to_ptr(db).to_node(&db.parse(file_id).syntax_node()) } HirFileIdRepr::MacroFile(macro_file) => { - let expansion_info = ctx.cache.get_or_insert_expansion(sema, macro_file); + let expansion_info = ctx.cache.get_or_insert_expansion(ctx.db, macro_file); it.to_ptr(db).to_node(&expansion_info.expanded().value) } }; diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs index ec65ea9a9a8..d5dfb985718 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs @@ -56,7 +56,7 @@ impl ChildBySource for ImplId { res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id); }, ); - data.items.iter().for_each(|&item| { + data.items.iter().for_each(|&(_, item)| { add_assoc_item(db, res, file_id, item); }); } diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs index b5cc440fc22..3c9e7065c41 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs @@ -110,10 +110,7 @@ use syntax::{ AstNode, AstPtr, SyntaxNode, }; -use crate::{ - db::HirDatabase, semantics::child_by_source::ChildBySource, InFile, InlineAsmOperand, - SemanticsImpl, -}; +use crate::{db::HirDatabase, semantics::child_by_source::ChildBySource, InFile, InlineAsmOperand}; #[derive(Default)] pub(super) struct SourceToDefCache { @@ -121,9 +118,21 @@ pub(super) struct SourceToDefCache { expansion_info_cache: FxHashMap<MacroFileId, ExpansionInfo>, pub(super) file_to_def_cache: FxHashMap<FileId, SmallVec<[ModuleId; 1]>>, pub(super) included_file_cache: FxHashMap<EditionedFileId, Option<MacroFileId>>, + /// Rootnode to HirFileId cache + pub(super) root_to_file_cache: FxHashMap<SyntaxNode, HirFileId>, } impl SourceToDefCache { + pub(super) fn cache( + root_to_file_cache: &mut FxHashMap<SyntaxNode, HirFileId>, + root_node: SyntaxNode, + file_id: HirFileId, + ) { + assert!(root_node.parent().is_none()); + let prev = root_to_file_cache.insert(root_node, file_id); + assert!(prev.is_none() || prev == Some(file_id)); + } + pub(super) fn get_or_insert_include_for( &mut self, db: &dyn HirDatabase, @@ -143,14 +152,14 @@ impl SourceToDefCache { pub(super) fn get_or_insert_expansion( &mut self, - sema: &SemanticsImpl<'_>, + db: &dyn HirDatabase, macro_file: MacroFileId, ) -> &ExpansionInfo { self.expansion_info_cache.entry(macro_file).or_insert_with(|| { - let exp_info = macro_file.expansion_info(sema.db.upcast()); + let exp_info = macro_file.expansion_info(db.upcast()); let InMacroFile { file_id, value } = exp_info.expanded(); - sema.cache(value, file_id.into()); + Self::cache(&mut self.root_to_file_cache, value, file_id.into()); exp_info }) @@ -520,18 +529,11 @@ impl SourceToDefCtx<'_, '_> { node: InFile<&SyntaxNode>, mut cb: impl FnMut(&mut Self, InFile<SyntaxNode>) -> Option<T>, ) -> Option<T> { - use hir_expand::MacroFileIdExt; let parent = |this: &mut Self, node: InFile<&SyntaxNode>| match node.value.parent() { Some(parent) => Some(node.with_value(parent)), None => { let macro_file = node.file_id.macro_file()?; - - let expansion_info = this - .cache - .expansion_info_cache - .entry(macro_file) - .or_insert_with(|| macro_file.expansion_info(this.db.upcast())); - + let expansion_info = this.cache.get_or_insert_expansion(this.db, macro_file); expansion_info.arg().map(|node| node?.parent()).transpose() } }; diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs index b699ccde412..6b78d7a3631 100644 --- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs +++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs @@ -322,6 +322,68 @@ impl SourceAnalyzer { } } + // If the method is into(), try_into(), parse(), resolve it to from, try_from, from_str. + pub(crate) fn resolve_known_blanket_dual_impls( + &self, + db: &dyn HirDatabase, + call: &ast::MethodCallExpr, + ) -> Option<Function> { + // e.g. if the method call is let b = a.into(), + // - receiver_type is A (type of a) + // - return_type is B (type of b) + // We will find the definition of B::from(a: A). + let callable = self.resolve_method_call_as_callable(db, call)?; + let (_, receiver_type) = callable.receiver_param(db)?; + let return_type = callable.return_type(); + let (search_method, substs) = match call.name_ref()?.text().as_str() { + "into" => { + let trait_ = + self.resolver.resolve_known_trait(db.upcast(), &path![core::convert::From])?; + ( + self.trait_fn(db, trait_, "from")?, + hir_ty::TyBuilder::subst_for_def(db, trait_, None) + .push(return_type.ty) + .push(receiver_type.ty) + .build(), + ) + } + "try_into" => { + let trait_ = self + .resolver + .resolve_known_trait(db.upcast(), &path![core::convert::TryFrom])?; + ( + self.trait_fn(db, trait_, "try_from")?, + hir_ty::TyBuilder::subst_for_def(db, trait_, None) + // If the method is try_into() or parse(), return_type is Result<T, Error>. + // Get T from type arguments of Result<T, Error>. + .push(return_type.type_arguments().next()?.ty) + .push(receiver_type.ty) + .build(), + ) + } + "parse" => { + let trait_ = + self.resolver.resolve_known_trait(db.upcast(), &path![core::str::FromStr])?; + ( + self.trait_fn(db, trait_, "from_str")?, + hir_ty::TyBuilder::subst_for_def(db, trait_, None) + .push(return_type.type_arguments().next()?.ty) + .build(), + ) + } + _ => return None, + }; + + let found_method = self.resolve_impl_method_or_trait_def(db, search_method, substs); + // If found_method == search_method, the method in trait itself is resolved. + // It means the blanket dual impl is not found. + if found_method == search_method { + None + } else { + Some(found_method.into()) + } + } + pub(crate) fn resolve_expr_as_callable( &self, db: &dyn HirDatabase, @@ -1247,6 +1309,18 @@ impl SourceAnalyzer { Some((trait_id, fn_id)) } + fn trait_fn( + &self, + db: &dyn HirDatabase, + trait_id: TraitId, + method_name: &str, + ) -> Option<FunctionId> { + db.trait_data(trait_id).items.iter().find_map(|(item_name, item)| match item { + AssocItemId::FunctionId(t) if item_name.as_str() == method_name => Some(*t), + _ => None, + }) + } + fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> { self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?) } diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs index f8416f86bf9..a6b8ed70c36 100644 --- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs +++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs @@ -1,27 +1,34 @@ //! File symbol extraction. +use either::Either; use hir_def::{ db::DefDatabase, - item_scope::ItemInNs, + item_scope::{ImportId, ImportOrExternCrate}, + per_ns::Item, src::{HasChildSource, HasSource}, - AdtId, AssocItemId, DefWithBodyId, HasModule, ImplId, Lookup, MacroId, ModuleDefId, ModuleId, - TraitId, + visibility::{Visibility, VisibilityExplicitness}, + AdtId, AssocItemId, DefWithBodyId, ExternCrateId, HasModule, ImplId, Lookup, MacroId, + ModuleDefId, ModuleId, TraitId, }; -use hir_expand::HirFileId; +use hir_expand::{name::Name, HirFileId}; use hir_ty::{ db::HirDatabase, display::{hir_display_with_types_map, HirDisplay}, }; +use intern::Symbol; +use rustc_hash::FxHashMap; use span::Edition; use syntax::{ast::HasName, AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, ToSmolStr}; use crate::{Module, ModuleDef, Semantics}; +pub type FxIndexSet<T> = indexmap::IndexSet<T, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>; + /// The actual data that is stored in the index. It should be as compact as /// possible. #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct FileSymbol { - pub name: SmolStr, + pub name: Symbol, pub def: ModuleDef, pub loc: DeclarationLocation, pub container_name: Option<SmolStr>, @@ -37,7 +44,7 @@ pub struct DeclarationLocation { /// This points to the whole syntax node of the declaration. pub ptr: SyntaxNodePtr, /// This points to the [`syntax::ast::Name`] identifier of the declaration. - pub name_ptr: AstPtr<syntax::ast::Name>, + pub name_ptr: AstPtr<Either<syntax::ast::Name, syntax::ast::NameRef>>, } impl DeclarationLocation { @@ -55,7 +62,7 @@ struct SymbolCollectorWork { pub struct SymbolCollector<'a> { db: &'a dyn HirDatabase, - symbols: Vec<FileSymbol>, + symbols: FxIndexSet<FileSymbol>, work: Vec<SymbolCollectorWork>, current_container_name: Option<SmolStr>, edition: Edition, @@ -86,11 +93,11 @@ impl<'a> SymbolCollector<'a> { } } - pub fn finish(self) -> Vec<FileSymbol> { - self.symbols + pub fn finish(self) -> Box<[FileSymbol]> { + self.symbols.into_iter().collect() } - pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Vec<FileSymbol> { + pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Box<[FileSymbol]> { let mut symbol_collector = SymbolCollector::new(db); symbol_collector.collect(module); symbol_collector.finish() @@ -104,96 +111,174 @@ impl<'a> SymbolCollector<'a> { } fn collect_from_module(&mut self, module_id: ModuleId) { - let def_map = module_id.def_map(self.db.upcast()); - let scope = &def_map[module_id.local_id].scope; - - for module_def_id in scope.declarations() { - match module_def_id { - ModuleDefId::ModuleId(id) => self.push_module(id), + let push_decl = |this: &mut Self, def, name| { + match def { + ModuleDefId::ModuleId(id) => this.push_module(id, name), ModuleDefId::FunctionId(id) => { - self.push_decl(id, false); - self.collect_from_body(id); + this.push_decl(id, name, false); + this.collect_from_body(id); } - ModuleDefId::AdtId(AdtId::StructId(id)) => self.push_decl(id, false), - ModuleDefId::AdtId(AdtId::EnumId(id)) => self.push_decl(id, false), - ModuleDefId::AdtId(AdtId::UnionId(id)) => self.push_decl(id, false), + ModuleDefId::AdtId(AdtId::StructId(id)) => this.push_decl(id, name, false), + ModuleDefId::AdtId(AdtId::EnumId(id)) => this.push_decl(id, name, false), + ModuleDefId::AdtId(AdtId::UnionId(id)) => this.push_decl(id, name, false), ModuleDefId::ConstId(id) => { - self.push_decl(id, false); - self.collect_from_body(id); + this.push_decl(id, name, false); + this.collect_from_body(id); } ModuleDefId::StaticId(id) => { - self.push_decl(id, false); - self.collect_from_body(id); + this.push_decl(id, name, false); + this.collect_from_body(id); } ModuleDefId::TraitId(id) => { - self.push_decl(id, false); - self.collect_from_trait(id); + this.push_decl(id, name, false); + this.collect_from_trait(id); } ModuleDefId::TraitAliasId(id) => { - self.push_decl(id, false); + this.push_decl(id, name, false); } ModuleDefId::TypeAliasId(id) => { - self.push_decl(id, false); + this.push_decl(id, name, false); } ModuleDefId::MacroId(id) => match id { - MacroId::Macro2Id(id) => self.push_decl(id, false), - MacroId::MacroRulesId(id) => self.push_decl(id, false), - MacroId::ProcMacroId(id) => self.push_decl(id, false), + MacroId::Macro2Id(id) => this.push_decl(id, name, false), + MacroId::MacroRulesId(id) => this.push_decl(id, name, false), + MacroId::ProcMacroId(id) => this.push_decl(id, name, false), }, // Don't index these. ModuleDefId::BuiltinType(_) => {} ModuleDefId::EnumVariantId(_) => {} } - } + }; - for impl_id in scope.impls() { - self.collect_from_impl(impl_id); - } + // Nested trees are very common, so a cache here will hit a lot. + let import_child_source_cache = &mut FxHashMap::default(); + + let mut push_import = |this: &mut Self, i: ImportId, name: &Name, def: ModuleDefId| { + let source = import_child_source_cache + .entry(i.import) + .or_insert_with(|| i.import.child_source(this.db.upcast())); + let Some(use_tree_src) = source.value.get(i.idx) else { return }; + let Some(name_ptr) = use_tree_src + .rename() + .and_then(|rename| rename.name()) + .map(Either::Left) + .or_else(|| use_tree_src.path()?.segment()?.name_ref().map(Either::Right)) + .map(|it| AstPtr::new(&it)) + else { + return; + }; + let dec_loc = DeclarationLocation { + hir_file_id: source.file_id, + ptr: SyntaxNodePtr::new(use_tree_src.syntax()), + name_ptr, + }; + this.symbols.insert(FileSymbol { + name: name.symbol().clone(), + def: def.into(), + container_name: this.current_container_name.clone(), + loc: dec_loc, + is_alias: false, + is_assoc: false, + }); + }; - // Record renamed imports. - // FIXME: In case it imports multiple items under different namespaces we just pick one arbitrarily - // for now. - for id in scope.imports() { - let source = id.import.child_source(self.db.upcast()); - let Some(use_tree_src) = source.value.get(id.idx) else { continue }; - let Some(rename) = use_tree_src.rename() else { continue }; - let Some(name) = rename.name() else { continue }; - - let res = scope.fully_resolve_import(self.db.upcast(), id); - res.iter_items().for_each(|(item, _)| { - let def = match item { - ItemInNs::Types(def) | ItemInNs::Values(def) => def, - ItemInNs::Macros(def) => ModuleDefId::from(def), - } - .into(); + let push_extern_crate = + |this: &mut Self, i: ExternCrateId, name: &Name, def: ModuleDefId| { + let loc = i.lookup(this.db.upcast()); + let source = loc.source(this.db.upcast()); + let Some(name_ptr) = source + .value + .rename() + .and_then(|rename| rename.name()) + .map(Either::Left) + .or_else(|| source.value.name_ref().map(Either::Right)) + .map(|it| AstPtr::new(&it)) + else { + return; + }; let dec_loc = DeclarationLocation { hir_file_id: source.file_id, - ptr: SyntaxNodePtr::new(use_tree_src.syntax()), - name_ptr: AstPtr::new(&name), + ptr: SyntaxNodePtr::new(source.value.syntax()), + name_ptr, }; - - self.symbols.push(FileSymbol { - name: name.text().into(), - def, - container_name: self.current_container_name.clone(), + this.symbols.insert(FileSymbol { + name: name.symbol().clone(), + def: def.into(), + container_name: this.current_container_name.clone(), loc: dec_loc, is_alias: false, is_assoc: false, }); - }); + }; + + let is_explicit_import = |vis| { + match vis { + Visibility::Module(_, VisibilityExplicitness::Explicit) => true, + Visibility::Module(_, VisibilityExplicitness::Implicit) => { + // consider imports in the crate root explicit, as these are visibly + // crate-wide anyways + module_id.is_crate_root() + } + Visibility::Public => true, + } + }; + + let def_map = module_id.def_map(self.db.upcast()); + let scope = &def_map[module_id.local_id].scope; + + for impl_id in scope.impls() { + self.collect_from_impl(impl_id); + } + + for (name, Item { def, vis, import }) in scope.types() { + if let Some(i) = import { + if is_explicit_import(vis) { + match i { + ImportOrExternCrate::Import(i) => push_import(self, i, name, def), + ImportOrExternCrate::ExternCrate(i) => { + push_extern_crate(self, i, name, def) + } + } + } + continue; + } + // self is a declaration + push_decl(self, def, name) + } + + for (name, Item { def, vis, import }) in scope.macros() { + if let Some(i) = import { + if is_explicit_import(vis) { + push_import(self, i, name, def.into()); + } + continue; + } + // self is a declaration + push_decl(self, def.into(), name) + } + + for (name, Item { def, vis, import }) in scope.values() { + if let Some(i) = import { + if is_explicit_import(vis) { + push_import(self, i, name, def); + } + continue; + } + // self is a declaration + push_decl(self, def, name) } for const_id in scope.unnamed_consts() { self.collect_from_body(const_id); } - for (_, id) in scope.legacy_macros() { + for (name, id) in scope.legacy_macros() { for &id in id { if id.module(self.db.upcast()) == module_id { match id { - MacroId::Macro2Id(id) => self.push_decl(id, false), - MacroId::MacroRulesId(id) => self.push_decl(id, false), - MacroId::ProcMacroId(id) => self.push_decl(id, false), + MacroId::Macro2Id(id) => self.push_decl(id, name, false), + MacroId::MacroRulesId(id) => self.push_decl(id, name, false), + MacroId::ProcMacroId(id) => self.push_decl(id, name, false), } } } @@ -223,8 +308,8 @@ impl<'a> SymbolCollector<'a> { .to_smolstr(), ); self.with_container_name(impl_name, |s| { - for &assoc_item_id in impl_data.items.iter() { - s.push_assoc_item(assoc_item_id) + for &(ref name, assoc_item_id) in &impl_data.items { + s.push_assoc_item(assoc_item_id, name) } }) } @@ -232,8 +317,8 @@ impl<'a> SymbolCollector<'a> { fn collect_from_trait(&mut self, trait_id: TraitId) { let trait_data = self.db.trait_data(trait_id); self.with_container_name(Some(trait_data.name.as_str().into()), |s| { - for &(_, assoc_item_id) in &trait_data.items { - s.push_assoc_item(assoc_item_id); + for &(ref name, assoc_item_id) in &trait_data.items { + s.push_assoc_item(assoc_item_id, name); } }); } @@ -266,15 +351,15 @@ impl<'a> SymbolCollector<'a> { } } - fn push_assoc_item(&mut self, assoc_item_id: AssocItemId) { + fn push_assoc_item(&mut self, assoc_item_id: AssocItemId, name: &Name) { match assoc_item_id { - AssocItemId::FunctionId(id) => self.push_decl(id, true), - AssocItemId::ConstId(id) => self.push_decl(id, true), - AssocItemId::TypeAliasId(id) => self.push_decl(id, true), + AssocItemId::FunctionId(id) => self.push_decl(id, name, true), + AssocItemId::ConstId(id) => self.push_decl(id, name, true), + AssocItemId::TypeAliasId(id) => self.push_decl(id, name, true), } } - fn push_decl<'db, L>(&mut self, id: L, is_assoc: bool) + fn push_decl<'db, L>(&mut self, id: L, name: &Name, is_assoc: bool) where L: Lookup<Database<'db> = dyn DefDatabase + 'db> + Into<ModuleDefId>, <L as Lookup>::Data: HasSource, @@ -287,13 +372,13 @@ impl<'a> SymbolCollector<'a> { let dec_loc = DeclarationLocation { hir_file_id: source.file_id, ptr: SyntaxNodePtr::new(source.value.syntax()), - name_ptr: AstPtr::new(&name_node), + name_ptr: AstPtr::new(&name_node).wrap_left(), }; if let Some(attrs) = def.attrs(self.db) { for alias in attrs.doc_aliases() { - self.symbols.push(FileSymbol { - name: alias.as_str().into(), + self.symbols.insert(FileSymbol { + name: alias.clone(), def, loc: dec_loc.clone(), container_name: self.current_container_name.clone(), @@ -303,8 +388,8 @@ impl<'a> SymbolCollector<'a> { } } - self.symbols.push(FileSymbol { - name: name_node.text().into(), + self.symbols.insert(FileSymbol { + name: name.symbol().clone(), def, container_name: self.current_container_name.clone(), loc: dec_loc, @@ -313,7 +398,7 @@ impl<'a> SymbolCollector<'a> { }); } - fn push_module(&mut self, module_id: ModuleId) { + fn push_module(&mut self, module_id: ModuleId, name: &Name) { let def_map = module_id.def_map(self.db.upcast()); let module_data = &def_map[module_id.local_id]; let Some(declaration) = module_data.origin.declaration() else { return }; @@ -322,15 +407,15 @@ impl<'a> SymbolCollector<'a> { let dec_loc = DeclarationLocation { hir_file_id: declaration.file_id, ptr: SyntaxNodePtr::new(module.syntax()), - name_ptr: AstPtr::new(&name_node), + name_ptr: AstPtr::new(&name_node).wrap_left(), }; let def = ModuleDef::Module(module_id.into()); if let Some(attrs) = def.attrs(self.db) { for alias in attrs.doc_aliases() { - self.symbols.push(FileSymbol { - name: alias.as_str().into(), + self.symbols.insert(FileSymbol { + name: alias.clone(), def, loc: dec_loc.clone(), container_name: self.current_container_name.clone(), @@ -340,8 +425,8 @@ impl<'a> SymbolCollector<'a> { } } - self.symbols.push(FileSymbol { - name: name_node.text().into(), + self.symbols.insert(FileSymbol { + name: name.symbol().clone(), def: ModuleDef::Module(module_id.into()), container_name: self.current_container_name.clone(), loc: dec_loc, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs index 074d943719f..64e77b2d698 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_context.rs @@ -109,6 +109,10 @@ impl<'a> AssistContext<'a> { self.trimmed_range } + pub(crate) fn source_file(&self) -> &SourceFile { + &self.source_file + } + pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { self.source_file.syntax().token_at_offset(self.offset()) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs index 24b34f140bd..5899ec5a005 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_match_arms.rs @@ -212,8 +212,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) !hidden }) .map(|(pat, _)| { - make::match_arm(iter::once(pat), None, make::ext::expr_todo()) - .clone_for_update() + make::match_arm(pat, None, make::ext::expr_todo()).clone_for_update() }); let catch_all_arm = new_match_arm_list @@ -243,12 +242,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>) if needs_catch_all_arm && !has_catch_all_arm { cov_mark::hit!(added_wildcard_pattern); - let arm = make::match_arm( - iter::once(make::wildcard_pat().into()), - None, - make::ext::expr_todo(), - ) - .clone_for_update(); + let arm = + make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo()) + .clone_for_update(); todo_placeholders.push(arm.expr().unwrap()); added_arms.push(arm); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs index 62700ab1809..04d63f5bc8f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_turbo_fish.rs @@ -189,7 +189,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti /// This will create a turbofish generic arg list corresponding to the number of arguments fn get_fish_head(make: &SyntaxFactory, number_of_arguments: usize) -> ast::GenericArgList { let args = (0..number_of_arguments).map(|_| make::type_arg(make::ty_placeholder()).into()); - make.turbofish_generic_arg_list(args) + make.generic_arg_list(args, true) } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs index f178a7e0cec..70fb5680052 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs @@ -252,7 +252,7 @@ fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) { /// Add bang and parentheses to the expression. fn add_bang_paren(expr: ast::Expr) -> ast::Expr { - make::expr_prefix(T![!], make::expr_paren(expr)) + make::expr_prefix(T![!], make::expr_paren(expr)).into() } #[cfg(test)] diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs index f699899066b..cbd39796241 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/bool_to_enum.rs @@ -195,6 +195,7 @@ fn bool_expr_to_enum_expr(expr: ast::Expr) -> ast::Expr { make::tail_only_block_expr(true_expr), Some(ast::ElseBranch::Block(make::tail_only_block_expr(false_expr))), ) + .into() } } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs index 79f303b37a4..bb04a43cf96 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs @@ -507,7 +507,7 @@ fn wrap_capture_in_deref_if_needed( if does_autoderef { return capture_name; } - make::expr_prefix(T![*], capture_name) + make::expr_prefix(T![*], capture_name).into() } fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Expr { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs index 67c72a93dad..dd2e9cbcb5f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_from_to_tryfrom.rs @@ -97,7 +97,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_> ); for r in return_exprs { - let t = r.expr().unwrap_or_else(make::expr_unit); + let t = r.expr().unwrap_or_else(make::ext::expr_unit); ted::replace(t.syntax(), wrap_ok(t.clone()).syntax().clone_for_update()); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs index 434daa279ca..0b92beefbcd 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_while_to_loop.rs @@ -60,7 +60,7 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>) .indent(while_indent_level); let block_expr = if is_pattern_cond(while_cond.clone()) { let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into())); - let stmts = iter::once(make::expr_stmt(if_expr).into()); + let stmts = iter::once(make::expr_stmt(if_expr.into()).into()); make::block_expr(stmts, None) } else { let if_cond = invert_boolean_expression(while_cond); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs index 7df6ca1565f..39142d60620 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/destructure_tuple_binding.rs @@ -1128,7 +1128,10 @@ fn main { destructure_tuple_binding_impl(acc, ctx, false) } - pub(crate) fn check_in_place_assist(ra_fixture_before: &str, ra_fixture_after: &str) { + pub(crate) fn check_in_place_assist( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, + ) { check_assist_by_label( in_place_assist, ra_fixture_before, @@ -1138,7 +1141,10 @@ fn main { ); } - pub(crate) fn check_sub_pattern_assist(ra_fixture_before: &str, ra_fixture_after: &str) { + pub(crate) fn check_sub_pattern_assist( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, + ) { check_assist_by_label( assist, ra_fixture_before, diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs index 0d1b6af7204..967da41c15f 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs @@ -1533,7 +1533,7 @@ impl FlowHandler { .into(), call_expr, ); - make::expr_if(condition.into(), block, None) + make::expr_if(condition.into(), block, None).into() } FlowHandler::IfOption { action } => { let path = make::ext::ident_path("Some"); @@ -1544,7 +1544,7 @@ impl FlowHandler { let action_expr = action.make_result_handler(Some(value)); let action_stmt = make::expr_stmt(action_expr); let then = make::block_expr(iter::once(action_stmt.into()), None); - make::expr_if(cond.into(), then, None) + make::expr_if(cond.into(), then, None).into() } FlowHandler::MatchOption { none } => { let some_name = "value"; @@ -1554,15 +1554,15 @@ impl FlowHandler { let value_pat = make::ext::simple_ident_pat(make::name(some_name)); let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); let value = make::expr_path(make::ext::ident_path(some_name)); - make::match_arm(iter::once(pat.into()), None, value) + make::match_arm(pat.into(), None, value) }; let none_arm = { let path = make::ext::ident_path("None"); let pat = make::path_pat(path); - make::match_arm(iter::once(pat), None, none.make_result_handler(None)) + make::match_arm(pat, None, none.make_result_handler(None)) }; let arms = make::match_arm_list(vec![some_arm, none_arm]); - make::expr_match(call_expr, arms) + make::expr_match(call_expr, arms).into() } FlowHandler::MatchResult { err } => { let ok_name = "value"; @@ -1573,21 +1573,17 @@ impl FlowHandler { let value_pat = make::ext::simple_ident_pat(make::name(ok_name)); let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); let value = make::expr_path(make::ext::ident_path(ok_name)); - make::match_arm(iter::once(pat.into()), None, value) + make::match_arm(pat.into(), None, value) }; let err_arm = { let path = make::ext::ident_path("Err"); let value_pat = make::ext::simple_ident_pat(make::name(err_name)); let pat = make::tuple_struct_pat(path, iter::once(value_pat.into())); let value = make::expr_path(make::ext::ident_path(err_name)); - make::match_arm( - iter::once(pat.into()), - None, - err.make_result_handler(Some(value)), - ) + make::match_arm(pat.into(), None, err.make_result_handler(Some(value))) }; let arms = make::match_arm_list(vec![ok_arm, err_arm]); - make::expr_match(call_expr, arms) + make::expr_match(call_expr, arms).into() } } } @@ -1879,7 +1875,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) - .iter() .map(|var| path_expr_from_local(ctx, var.local, fun.mods.edition)); let expr = make::expr_tuple(exprs); - tail_expr = Some(expr); + tail_expr = Some(expr.into()); } }, }; @@ -1910,7 +1906,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) - match &handler { FlowHandler::None => block, FlowHandler::Try { kind } => { - let block = with_default_tail_expr(block, make::expr_unit()); + let block = with_default_tail_expr(block, make::ext::expr_unit()); map_tail_expr(block, |tail_expr| { let constructor = match kind { TryKind::Option => "Some", @@ -1924,7 +1920,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) - FlowHandler::If { .. } => { let controlflow_continue = make::expr_call( make::expr_path(make::path_from_text("ControlFlow::Continue")), - make::arg_list(iter::once(make::expr_unit())), + make::arg_list([make::ext::expr_unit()]), ); with_tail_expr(block, controlflow_continue) } @@ -2127,17 +2123,17 @@ fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Op FlowHandler::None | FlowHandler::Try { .. } => return None, FlowHandler::If { .. } => make::expr_call( make::expr_path(make::path_from_text("ControlFlow::Break")), - make::arg_list(iter::once(make::expr_unit())), + make::arg_list([make::ext::expr_unit()]), ), FlowHandler::IfOption { .. } => { - let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); - let args = make::arg_list(iter::once(expr)); + let expr = arg_expr.unwrap_or_else(make::ext::expr_unit); + let args = make::arg_list([expr]); make::expr_call(make::expr_path(make::ext::ident_path("Some")), args) } FlowHandler::MatchOption { .. } => make::expr_path(make::ext::ident_path("None")), FlowHandler::MatchResult { .. } => { - let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new())); - let args = make::arg_list(iter::once(expr)); + let expr = arg_expr.unwrap_or_else(make::ext::expr_unit); + let args = make::arg_list([expr]); make::expr_call(make::expr_path(make::ext::ident_path("Err")), args) } }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs index 0cc807aff64..97321f4ec1e 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs @@ -4,6 +4,7 @@ use ide_db::{ syntax_helpers::{suggest_name, LexedStr}, }; use syntax::{ + algo::ancestors_at_offset, ast::{ self, edit::IndentLevel, edit_in_place::Indent, make, syntax_factory::SyntaxFactory, AstNode, @@ -68,7 +69,10 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op let node = if ctx.has_empty_selection() { if let Some(t) = ctx.token_at_offset().find(|it| it.kind() == T![;]) { t.parent().and_then(ast::ExprStmt::cast)?.syntax().clone() - } else if let Some(expr) = ctx.find_node_at_offset::<ast::Expr>() { + } else if let Some(expr) = ancestors_at_offset(ctx.source_file().syntax(), ctx.offset()) + .next() + .and_then(ast::Expr::cast) + { expr.syntax().ancestors().find_map(valid_target_expr)?.syntax().clone() } else { return None; @@ -469,11 +473,11 @@ mod tests { extract_variable, r#" fn main() -> i32 { - if true { + if$0 true { 1 } else { 2 - }$0 + } } "#, r#" @@ -581,11 +585,11 @@ fn main() { extract_variable, r#" fn main() -> i32 { - if true { + if$0 true { 1 } else { 2 - }$0 + } } "#, r#" @@ -676,11 +680,11 @@ fn main() { extract_variable, r#" fn main() -> i32 { - if true { + if$0 true { 1 } else { 2 - }$0 + } } "#, r#" diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs index c879a4a3d95..ac58af62525 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs @@ -933,7 +933,7 @@ mod tests_setter { use super::*; - fn check_not_applicable(ra_fixture: &str) { + fn check_not_applicable(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_assist_not_applicable(generate_setter, ra_fixture) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs index d558ec3bec7..cd6f900ba15 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs @@ -38,21 +38,21 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let unexpanded = ctx.find_node_at_offset::<ast::MacroCall>()?; let macro_call = ctx.sema.to_def(&unexpanded)?; - let expanded = ctx.sema.parse_or_expand(macro_call.as_file()); - let span_map = ctx.sema.db.expansion_span_map(macro_call.as_macro_file()); - let expanded = prettify_macro_expansion( - ctx.db(), - expanded, - &span_map, - ctx.sema.file_to_module_def(ctx.file_id())?.krate().into(), - ); + let target_crate_id = ctx.sema.file_to_module_def(ctx.file_id())?.krate().into(); let text_range = unexpanded.syntax().text_range(); acc.add( AssistId("inline_macro", AssistKind::RefactorInline), "Inline macro".to_owned(), text_range, - |builder| builder.replace(text_range, expanded.to_string()), + |builder| { + let expanded = ctx.sema.parse_or_expand(macro_call.as_file()); + let span_map = ctx.sema.db.expansion_span_map(macro_call.as_macro_file()); + // Don't call `prettify_macro_expansion()` outside the actual assist action; it does some heavy rowan tree manipulation, + // which can be very costly for big macros when it is done *even without the assist being invoked*. + let expanded = prettify_macro_expansion(ctx.db(), expanded, &span_map, target_crate_id); + builder.replace(text_range, expanded.to_string()) + }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs index f0c96fe3cb8..a487960d8d4 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_guard.rs @@ -61,7 +61,7 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>) }; edit.delete(guard.syntax().text_range()); - edit.replace_ast(arm_expr, if_expr); + edit.replace_ast(arm_expr, if_expr.into()); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs index 94274f6d17c..1f57f7d3d37 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs @@ -102,7 +102,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt }; (range, None) }, - _ => (macro_call.syntax().text_range(), Some(make::expr_unit())), + _ => (macro_call.syntax().text_range(), Some(make::ext::expr_unit())), } } } @@ -152,7 +152,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt exprs => { let exprs = exprs.iter().cloned().map(replace_nested_dbgs); let expr = make::expr_tuple(exprs); - (macro_call.syntax().text_range(), Some(expr)) + (macro_call.syntax().text_range(), Some(expr.into())) } }) } @@ -209,7 +209,10 @@ mod tests { use super::*; - fn check(ra_fixture_before: &str, ra_fixture_after: &str) { + fn check( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, + ) { check_assist( remove_dbg, &format!("fn main() {{\n{ra_fixture_before}\n}}"), diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs index b31d45e6d45..e324d6eaaad 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_if_let_with_match.rs @@ -1,4 +1,4 @@ -use std::iter::{self, successors}; +use std::iter::successors; use either::Either; use ide_db::{ @@ -8,11 +8,7 @@ use ide_db::{ RootDatabase, }; use syntax::{ - ast::{ - self, - edit::{AstNodeEdit, IndentLevel}, - make, HasName, - }, + ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory, HasName}, AstNode, TextRange, T, }; @@ -108,53 +104,58 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<' AssistId("replace_if_let_with_match", AssistKind::RefactorRewrite), format!("Replace if{let_} with match"), available_range, - move |edit| { + move |builder| { + let make = SyntaxFactory::new(); let match_expr = { - let else_arm = make_else_arm(ctx, else_block, &cond_bodies); + let else_arm = make_else_arm(ctx, &make, else_block, &cond_bodies); let make_match_arm = |(pat, body): (_, ast::BlockExpr)| { - let body = body.reset_indent().indent(IndentLevel(1)); + let body = make.block_expr(body.statements(), body.tail_expr()); + body.indent(IndentLevel::from(1)); + let body = unwrap_trivial_block(body); match pat { - Either::Left(pat) => { - make::match_arm(iter::once(pat), None, unwrap_trivial_block(body)) + Either::Left(pat) => make.match_arm(pat, None, body), + Either::Right(_) if !pat_seen => { + make.match_arm(make.literal_pat("true").into(), None, body) } - Either::Right(_) if !pat_seen => make::match_arm( - iter::once(make::literal_pat("true").into()), - None, - unwrap_trivial_block(body), - ), - Either::Right(expr) => make::match_arm( - iter::once(make::wildcard_pat().into()), - Some(expr), - unwrap_trivial_block(body), + Either::Right(expr) => make.match_arm( + make.wildcard_pat().into(), + Some(make.match_guard(expr)), + body, ), } }; - let arms = cond_bodies.into_iter().map(make_match_arm).chain(iter::once(else_arm)); - let match_expr = make::expr_match(scrutinee_to_be_expr, make::match_arm_list(arms)); - match_expr.indent(IndentLevel::from_node(if_expr.syntax())) + let arms = cond_bodies.into_iter().map(make_match_arm).chain([else_arm]); + let match_expr = make.expr_match(scrutinee_to_be_expr, make.match_arm_list(arms)); + match_expr.indent(IndentLevel::from_node(if_expr.syntax())); + match_expr.into() }; let has_preceding_if_expr = if_expr.syntax().parent().is_some_and(|it| ast::IfExpr::can_cast(it.kind())); let expr = if has_preceding_if_expr { // make sure we replace the `else if let ...` with a block so we don't end up with `else expr` - make::block_expr(None, Some(match_expr)).into() + make.block_expr([], Some(match_expr)).into() } else { match_expr }; - edit.replace_ast::<ast::Expr>(if_expr.into(), expr); + + let mut editor = builder.make_editor(if_expr.syntax()); + editor.replace(if_expr.syntax(), expr.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } fn make_else_arm( ctx: &AssistContext<'_>, + make: &SyntaxFactory, else_block: Option<ast::BlockExpr>, conditionals: &[(Either<ast::Pat, ast::Expr>, ast::BlockExpr)], ) -> ast::MatchArm { let (pattern, expr) = if let Some(else_block) = else_block { let pattern = match conditionals { - [(Either::Right(_), _)] => make::literal_pat("false").into(), + [(Either::Right(_), _)] => make.literal_pat("false").into(), [(Either::Left(pat), _)] => match ctx .sema .type_of_pat(pat) @@ -164,24 +165,24 @@ fn make_else_arm( if does_pat_match_variant(pat, &it.sad_pattern()) { it.happy_pattern_wildcard() } else if does_pat_variant_nested_or_literal(ctx, pat) { - make::wildcard_pat().into() + make.wildcard_pat().into() } else { it.sad_pattern() } } - None => make::wildcard_pat().into(), + None => make.wildcard_pat().into(), }, - _ => make::wildcard_pat().into(), + _ => make.wildcard_pat().into(), }; (pattern, unwrap_trivial_block(else_block)) } else { let pattern = match conditionals { - [(Either::Right(_), _)] => make::literal_pat("false").into(), - _ => make::wildcard_pat().into(), + [(Either::Right(_), _)] => make.literal_pat("false").into(), + _ => make.wildcard_pat().into(), }; - (pattern, make::expr_unit()) + (pattern, make.expr_unit()) }; - make::match_arm(iter::once(pattern), None, expr) + make.match_arm(pattern, None, expr) } // Assist: replace_match_with_if_let @@ -247,21 +248,21 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<' } _ => " let", }; - let target = match_expr.syntax().text_range(); acc.add( AssistId("replace_match_with_if_let", AssistKind::RefactorRewrite), format!("Replace match with if{let_}"), - target, - move |edit| { - fn make_block_expr(expr: ast::Expr) -> ast::BlockExpr { + match_expr.syntax().text_range(), + move |builder| { + let make = SyntaxFactory::new(); + let make_block_expr = |expr: ast::Expr| { // Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are // formatted without enclosing braces. If we encounter such block exprs, // wrap them in another BlockExpr. match expr { ast::Expr::BlockExpr(block) if block.modifier().is_none() => block, - expr => make::block_expr(iter::empty(), Some(expr)), + expr => make.block_expr([], Some(expr)), } - } + }; let condition = match if_let_pat { ast::Pat::LiteralPat(p) @@ -272,20 +273,25 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<' ast::Pat::LiteralPat(p) if p.literal().is_some_and(|it| it.token().kind() == T![false]) => { - make::expr_prefix(T![!], scrutinee) + make.expr_prefix(T![!], scrutinee).into() } - _ => make::expr_let(if_let_pat, scrutinee).into(), + _ => make.expr_let(if_let_pat, scrutinee).into(), }; - let then_block = make_block_expr(then_expr.reset_indent()); + let then_expr = then_expr.clone_for_update(); + then_expr.reindent_to(IndentLevel::single()); + let then_block = make_block_expr(then_expr); let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) }; - let if_let_expr = make::expr_if( + let if_let_expr = make.expr_if( condition, then_block, else_expr.map(make_block_expr).map(ast::ElseBranch::Block), - ) - .indent(IndentLevel::from_node(match_expr.syntax())); + ); + if_let_expr.indent(IndentLevel::from_node(match_expr.syntax())); - edit.replace_ast::<ast::Expr>(match_expr.into(), if_let_expr); + let mut editor = builder.make_editor(match_expr.syntax()); + editor.replace(match_expr.syntax(), if_let_expr.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs index c2be4593b97..c071d3022d2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_let_with_if_let.rs @@ -1,12 +1,6 @@ -use std::iter::once; - use ide_db::ty_filter::TryEnum; use syntax::{ - ast::{ - self, - edit::{AstNodeEdit, IndentLevel}, - make, - }, + ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory}, AstNode, T, }; @@ -47,7 +41,9 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_> AssistId("replace_let_with_if_let", AssistKind::RefactorRewrite), "Replace let with if let", target, - |edit| { + |builder| { + let mut editor = builder.make_editor(let_stmt.syntax()); + let make = SyntaxFactory::new(); let ty = ctx.sema.type_of_expr(&init); let happy_variant = ty .and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted())) @@ -55,17 +51,18 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_> let pat = match happy_variant { None => original_pat, Some(var_name) => { - make::tuple_struct_pat(make::ext::ident_path(var_name), once(original_pat)) - .into() + make.tuple_struct_pat(make.ident_path(var_name), [original_pat]).into() } }; - let block = - make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax())); - let if_ = make::expr_if(make::expr_let(pat, init).into(), block, None); - let stmt = make::expr_stmt(if_); + let block = make.block_expr([], None); + block.indent(IndentLevel::from_node(let_stmt.syntax())); + let if_expr = make.expr_if(make.expr_let(pat, init).into(), block, None); + let if_stmt = make.expr_stmt(if_expr.into()); - edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); + editor.replace(let_stmt.syntax(), if_stmt.syntax()); + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs index 2e26f59d030..88b50543dda 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs @@ -71,19 +71,17 @@ pub(crate) fn replace_try_expr_with_match( }; let happy_arm = make::match_arm( - iter::once( - try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()), - ), + try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()), None, make::expr_path(make::ext::ident_path("it")), ); - let sad_arm = make::match_arm(iter::once(sad_pat), None, sad_expr); + let sad_arm = make::match_arm(sad_pat, None, sad_expr); let match_arm_list = make::match_arm_list([happy_arm, sad_arm]); let expr_match = make::expr_match(expr, match_arm_list) .indent(IndentLevel::from_node(qm_kw_parent.syntax())); - edit.replace_ast::<ast::Expr>(qm_kw_parent.into(), expr_match); + edit.replace_ast::<ast::Expr>(qm_kw_parent.into(), expr_match.into()); }, ) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs index c6cffb5434a..6b9f661d4de 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unmerge_match_arm.rs @@ -54,13 +54,9 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O let pats_after = pipe_token .siblings_with_tokens(Direction::Next) .filter_map(|it| ast::Pat::cast(it.into_node()?)); - // FIXME: We should add a leading pipe if the original arm has one. - let new_match_arm = make::match_arm( - pats_after, - match_arm.guard().and_then(|guard| guard.condition()), - match_arm_body, - ) - .clone_for_update(); + let new_pat = make::or_pat(pats_after, or_pat.leading_pipe().is_some()); + let new_match_arm = + make::match_arm(new_pat, match_arm.guard(), match_arm_body).clone_for_update(); let mut pipe_index = pipe_token.index(); if pipe_token diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs index f3e7f5f4167..fd37140e9c2 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_block.rs @@ -61,7 +61,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option } } None => { - let empty_tuple = make::expr_tuple([]); + let empty_tuple = make::ext::expr_unit(); make::let_stmt(pattern, ty, Some(empty_tuple)).to_string() } }; diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs index 64d5e2c9b82..f647b531b77 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_return_type.rs @@ -1,11 +1,11 @@ +use either::Either; use ide_db::{ famous_defs::FamousDefs, syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, }; -use itertools::Itertools; use syntax::{ - ast::{self, Expr, HasGenericArgs}, - match_ast, AstNode, NodeOrToken, SyntaxKind, TextRange, + ast::{self, syntax_factory::SyntaxFactory, HasArgList, HasGenericArgs}, + match_ast, AstNode, NodeOrToken, SyntaxKind, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -39,11 +39,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let ret_type = ctx.find_node_at_offset::<ast::RetType>()?; let parent = ret_type.syntax().parent()?; - let body = match_ast! { + let body_expr = match_ast! { match parent { - ast::Fn(func) => func.body()?, + ast::Fn(func) => func.body()?.into(), ast::ClosureExpr(closure) => match closure.body()? { - Expr::BlockExpr(block) => block, + ast::Expr::BlockExpr(block) => block.into(), // closures require a block when a return type is specified _ => return None, }, @@ -65,72 +65,110 @@ pub(crate) fn unwrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> let happy_type = extract_wrapped_type(type_ref)?; acc.add(kind.assist_id(), kind.label(), type_ref.syntax().text_range(), |builder| { - let body = ast::Expr::BlockExpr(body); + let mut editor = builder.make_editor(&parent); + let make = SyntaxFactory::new(); let mut exprs_to_unwrap = Vec::new(); let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_unwrap, e); - walk_expr(&body, &mut |expr| { - if let Expr::ReturnExpr(ret_expr) = expr { + walk_expr(&body_expr, &mut |expr| { + if let ast::Expr::ReturnExpr(ret_expr) = expr { if let Some(ret_expr_arg) = &ret_expr.expr() { for_each_tail_expr(ret_expr_arg, tail_cb); } } }); - for_each_tail_expr(&body, tail_cb); + for_each_tail_expr(&body_expr, tail_cb); let is_unit_type = is_unit_type(&happy_type); if is_unit_type { - let mut text_range = ret_type.syntax().text_range(); - if let Some(NodeOrToken::Token(token)) = ret_type.syntax().next_sibling_or_token() { if token.kind() == SyntaxKind::WHITESPACE { - text_range = TextRange::new(text_range.start(), token.text_range().end()); + editor.delete(token); } } - builder.delete(text_range); + editor.delete(ret_type.syntax()); } else { - builder.replace(type_ref.syntax().text_range(), happy_type.syntax().text()); + editor.replace(type_ref.syntax(), happy_type.syntax()); } - for ret_expr_arg in exprs_to_unwrap { - let ret_expr_str = ret_expr_arg.to_string(); - - let needs_replacing = match kind { - UnwrapperKind::Option => ret_expr_str.starts_with("Some("), - UnwrapperKind::Result => { - ret_expr_str.starts_with("Ok(") || ret_expr_str.starts_with("Err(") - } - }; + let mut final_placeholder = None; + for tail_expr in exprs_to_unwrap { + match &tail_expr { + ast::Expr::CallExpr(call_expr) => { + let ast::Expr::PathExpr(path_expr) = call_expr.expr().unwrap() else { + continue; + }; + + let path_str = path_expr.path().unwrap().to_string(); + let needs_replacing = match kind { + UnwrapperKind::Option => path_str == "Some", + UnwrapperKind::Result => path_str == "Ok" || path_str == "Err", + }; + + if !needs_replacing { + continue; + } - if needs_replacing { - let arg_list = ret_expr_arg.syntax().children().find_map(ast::ArgList::cast); - if let Some(arg_list) = arg_list { + let arg_list = call_expr.arg_list().unwrap(); if is_unit_type { - match ret_expr_arg.syntax().prev_sibling_or_token() { - // Useful to delete the entire line without leaving trailing whitespaces - Some(whitespace) => { - let new_range = TextRange::new( - whitespace.text_range().start(), - ret_expr_arg.syntax().text_range().end(), - ); - builder.delete(new_range); + let tail_parent = tail_expr + .syntax() + .parent() + .and_then(Either::<ast::ReturnExpr, ast::StmtList>::cast) + .unwrap(); + match tail_parent { + Either::Left(ret_expr) => { + editor.replace(ret_expr.syntax(), make.expr_return(None).syntax()) } - None => { - builder.delete(ret_expr_arg.syntax().text_range()); + Either::Right(stmt_list) => { + let new_block = if stmt_list.statements().next().is_none() { + make.expr_empty_block() + } else { + make.block_expr(stmt_list.statements(), None) + }; + editor.replace( + stmt_list.syntax(), + new_block.stmt_list().unwrap().syntax(), + ); } } - } else { - builder.replace( - ret_expr_arg.syntax().text_range(), - arg_list.args().join(", "), + } else if let Some(first_arg) = arg_list.args().next() { + editor.replace(tail_expr.syntax(), first_arg.syntax()); + } + } + ast::Expr::PathExpr(path_expr) => { + let UnwrapperKind::Option = kind else { + continue; + }; + + if path_expr.path().unwrap().to_string() != "None" { + continue; + } + + let new_tail_expr = make.expr_unit(); + editor.replace(path_expr.syntax(), new_tail_expr.syntax()); + if let Some(cap) = ctx.config.snippet_cap { + editor.add_annotation( + new_tail_expr.syntax(), + builder.make_placeholder_snippet(cap), ); + + final_placeholder = Some(new_tail_expr); } } - } else if matches!(kind, UnwrapperKind::Option if ret_expr_str == "None") { - builder.replace(ret_expr_arg.syntax().text_range(), "()"); + _ => (), } } + + if let Some(cap) = ctx.config.snippet_cap { + if let Some(final_placeholder) = final_placeholder { + editor.add_annotation(final_placeholder.syntax(), builder.make_tabstop_after(cap)); + } + } + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }) } @@ -168,12 +206,12 @@ impl UnwrapperKind { fn tail_cb_impl(acc: &mut Vec<ast::Expr>, e: &ast::Expr) { match e { - Expr::BreakExpr(break_expr) => { + ast::Expr::BreakExpr(break_expr) => { if let Some(break_expr_arg) = break_expr.expr() { for_each_tail_expr(&break_expr_arg, &mut |e| tail_cb_impl(acc, e)) } } - Expr::ReturnExpr(_) => { + ast::Expr::ReturnExpr(_) => { // all return expressions have already been handled by the walk loop } e => acc.push(e.clone()), @@ -238,8 +276,7 @@ fn foo() -> Option<()$0> { } "#, r#" -fn foo() { -} +fn foo() {} "#, "Unwrap Option return type", ); @@ -254,8 +291,7 @@ fn foo() -> Option<()$0>{ } "#, r#" -fn foo() { -} +fn foo() {} "#, "Unwrap Option return type", ); @@ -280,7 +316,42 @@ fn foo() -> i32 { if true { 42 } else { - () + ${1:()}$0 + } +} +"#, + "Unwrap Option return type", + ); + } + + #[test] + fn unwrap_option_return_type_multi_none() { + check_assist_by_label( + unwrap_return_type, + r#" +//- minicore: option +fn foo() -> Option<i3$02> { + if false { + return None; + } + + if true { + Some(42) + } else { + None + } +} +"#, + r#" +fn foo() -> i32 { + if false { + return ${1:()}; + } + + if true { + 42 + } else { + ${2:()}$0 } } "#, @@ -1262,8 +1333,7 @@ fn foo() -> Result<(), Box<dyn Error$0>> { } "#, r#" -fn foo() { -} +fn foo() {} "#, "Unwrap Result return type", ); @@ -1278,8 +1348,7 @@ fn foo() -> Result<(), Box<dyn Error$0>>{ } "#, r#" -fn foo() { -} +fn foo() {} "#, "Unwrap Result return type", ); diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs index 658600cd2d0..0b145dcb06b 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/wrap_return_type.rs @@ -6,10 +6,9 @@ use ide_db::{ famous_defs::FamousDefs, syntax_helpers::node_ext::{for_each_tail_expr, walk_expr}, }; -use itertools::Itertools; use syntax::{ - ast::{self, make, Expr, HasGenericParams}, - match_ast, ted, AstNode, ToSmolStr, + ast::{self, syntax_factory::SyntaxFactory, Expr, HasGenericArgs, HasGenericParams}, + match_ast, AstNode, }; use crate::{AssistContext, AssistId, AssistKind, Assists}; @@ -43,11 +42,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists}; pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> { let ret_type = ctx.find_node_at_offset::<ast::RetType>()?; let parent = ret_type.syntax().parent()?; - let body = match_ast! { + let body_expr = match_ast! { match parent { - ast::Fn(func) => func.body()?, + ast::Fn(func) => func.body()?.into(), ast::ClosureExpr(closure) => match closure.body()? { - Expr::BlockExpr(block) => block, + Expr::BlockExpr(block) => block.into(), // closures require a block when a return type is specified _ => return None, }, @@ -75,56 +74,65 @@ pub(crate) fn wrap_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op kind.assist_id(), kind.label(), type_ref.syntax().text_range(), - |edit| { - let alias = wrapper_alias(ctx, &core_wrapper, type_ref, kind.symbol()); - let new_return_ty = - alias.unwrap_or_else(|| kind.wrap_type(type_ref)).clone_for_update(); - - let body = edit.make_mut(ast::Expr::BlockExpr(body.clone())); + |builder| { + let mut editor = builder.make_editor(&parent); + let make = SyntaxFactory::new(); + let alias = wrapper_alias(ctx, &make, &core_wrapper, type_ref, kind.symbol()); + let new_return_ty = alias.unwrap_or_else(|| match kind { + WrapperKind::Option => make.ty_option(type_ref.clone()), + WrapperKind::Result => make.ty_result(type_ref.clone(), make.ty_infer().into()), + }); let mut exprs_to_wrap = Vec::new(); let tail_cb = &mut |e: &_| tail_cb_impl(&mut exprs_to_wrap, e); - walk_expr(&body, &mut |expr| { + walk_expr(&body_expr, &mut |expr| { if let Expr::ReturnExpr(ret_expr) = expr { if let Some(ret_expr_arg) = &ret_expr.expr() { for_each_tail_expr(ret_expr_arg, tail_cb); } } }); - for_each_tail_expr(&body, tail_cb); + for_each_tail_expr(&body_expr, tail_cb); for ret_expr_arg in exprs_to_wrap { - let happy_wrapped = make::expr_call( - make::expr_path(make::ext::ident_path(kind.happy_ident())), - make::arg_list(iter::once(ret_expr_arg.clone())), - ) - .clone_for_update(); - ted::replace(ret_expr_arg.syntax(), happy_wrapped.syntax()); + let happy_wrapped = make.expr_call( + make.expr_path(make.ident_path(kind.happy_ident())), + make.arg_list(iter::once(ret_expr_arg.clone())), + ); + editor.replace(ret_expr_arg.syntax(), happy_wrapped.syntax()); } - let old_return_ty = edit.make_mut(type_ref.clone()); - ted::replace(old_return_ty.syntax(), new_return_ty.syntax()); + editor.replace(type_ref.syntax(), new_return_ty.syntax()); if let WrapperKind::Result = kind { // Add a placeholder snippet at the first generic argument that doesn't equal the return type. // This is normally the error type, but that may not be the case when we inserted a type alias. - let args = - new_return_ty.syntax().descendants().find_map(ast::GenericArgList::cast); - let error_type_arg = args.and_then(|list| { - list.generic_args().find(|arg| match arg { - ast::GenericArg::TypeArg(_) => { - arg.syntax().text() != type_ref.syntax().text() - } - ast::GenericArg::LifetimeArg(_) => false, - _ => true, - }) + let args = new_return_ty + .path() + .unwrap() + .segment() + .unwrap() + .generic_arg_list() + .unwrap(); + let error_type_arg = args.generic_args().find(|arg| match arg { + ast::GenericArg::TypeArg(_) => { + arg.syntax().text() != type_ref.syntax().text() + } + ast::GenericArg::LifetimeArg(_) => false, + _ => true, }); if let Some(error_type_arg) = error_type_arg { if let Some(cap) = ctx.config.snippet_cap { - edit.add_placeholder_snippet(cap, error_type_arg); + editor.add_annotation( + error_type_arg.syntax(), + builder.make_placeholder_snippet(cap), + ); } } } + + editor.add_mappings(make.finish_with_mappings()); + builder.add_file_edits(ctx.file_id(), editor); }, ); } @@ -176,22 +184,16 @@ impl WrapperKind { WrapperKind::Result => hir::sym::Result.clone(), } } - - fn wrap_type(&self, type_ref: &ast::Type) -> ast::Type { - match self { - WrapperKind::Option => make::ext::ty_option(type_ref.clone()), - WrapperKind::Result => make::ext::ty_result(type_ref.clone(), make::ty_placeholder()), - } - } } // Try to find an wrapper type alias in the current scope (shadowing the default). fn wrapper_alias( ctx: &AssistContext<'_>, + make: &SyntaxFactory, core_wrapper: &hir::Enum, ret_type: &ast::Type, wrapper: hir::Symbol, -) -> Option<ast::Type> { +) -> Option<ast::PathType> { let wrapper_path = hir::ModPath::from_segments( hir::PathKind::Plain, iter::once(hir::Name::new_symbol_root(wrapper)), @@ -207,25 +209,28 @@ fn wrapper_alias( }) .find_map(|alias| { let mut inserted_ret_type = false; - let generic_params = alias - .source(ctx.db())? - .value - .generic_param_list()? - .generic_params() - .map(|param| match param { - // Replace the very first type parameter with the functions return type. - ast::GenericParam::TypeParam(_) if !inserted_ret_type => { - inserted_ret_type = true; - ret_type.to_smolstr() + let generic_args = + alias.source(ctx.db())?.value.generic_param_list()?.generic_params().map(|param| { + match param { + // Replace the very first type parameter with the function's return type. + ast::GenericParam::TypeParam(_) if !inserted_ret_type => { + inserted_ret_type = true; + make.type_arg(ret_type.clone()).into() + } + ast::GenericParam::LifetimeParam(_) => { + make.lifetime_arg(make.lifetime("'_")).into() + } + _ => make.type_arg(make.ty_infer().into()).into(), } - ast::GenericParam::LifetimeParam(_) => make::lifetime("'_").to_smolstr(), - _ => make::ty_placeholder().to_smolstr(), - }) - .join(", "); + }); let name = alias.name(ctx.db()); - let name = name.as_str(); - Some(make::ty(&format!("{name}<{generic_params}>"))) + let generic_arg_list = make.generic_arg_list(generic_args, false); + let path = make.path_unqualified( + make.path_segment_generics(make.name_ref(name.as_str()), generic_arg_list), + ); + + Some(make.ty_path(path)) }) }) } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs index 0b1ff87c5c2..48d2af6d3ff 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs @@ -77,7 +77,11 @@ pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) { } #[track_caller] -pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_after: &str) { +pub(crate) fn check_assist( + assist: Handler, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { let ra_fixture_after = trim_indent(ra_fixture_after); check(assist, ra_fixture_before, ExpectedResult::After(&ra_fixture_after), None); } @@ -85,8 +89,8 @@ pub(crate) fn check_assist(assist: Handler, ra_fixture_before: &str, ra_fixture_ #[track_caller] pub(crate) fn check_assist_no_snippet_cap( assist: Handler, - ra_fixture_before: &str, - ra_fixture_after: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, ) { let ra_fixture_after = trim_indent(ra_fixture_after); check_with_config( @@ -101,8 +105,8 @@ pub(crate) fn check_assist_no_snippet_cap( #[track_caller] pub(crate) fn check_assist_import_one( assist: Handler, - ra_fixture_before: &str, - ra_fixture_after: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, ) { let ra_fixture_after = trim_indent(ra_fixture_after); check_with_config( @@ -118,8 +122,8 @@ pub(crate) fn check_assist_import_one( // so this is here to allow you choose. pub(crate) fn check_assist_by_label( assist: Handler, - ra_fixture_before: &str, - ra_fixture_after: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, label: &str, ) { let ra_fixture_after = trim_indent(ra_fixture_after); @@ -130,22 +134,36 @@ pub(crate) fn check_assist_by_label( // `extract_ranges` and mark the target as `<target> </target>` in the // fixture? #[track_caller] -pub(crate) fn check_assist_target(assist: Handler, ra_fixture: &str, target: &str) { +pub(crate) fn check_assist_target( + assist: Handler, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + target: &str, +) { check(assist, ra_fixture, ExpectedResult::Target(target), None); } #[track_caller] -pub(crate) fn check_assist_not_applicable(assist: Handler, ra_fixture: &str) { +pub(crate) fn check_assist_not_applicable( + assist: Handler, + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) { check(assist, ra_fixture, ExpectedResult::NotApplicable, None); } #[track_caller] -pub(crate) fn check_assist_not_applicable_by_label(assist: Handler, ra_fixture: &str, label: &str) { +pub(crate) fn check_assist_not_applicable_by_label( + assist: Handler, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + label: &str, +) { check(assist, ra_fixture, ExpectedResult::NotApplicable, Some(label)); } #[track_caller] -pub(crate) fn check_assist_not_applicable_for_import_one(assist: Handler, ra_fixture: &str) { +pub(crate) fn check_assist_not_applicable_for_import_one( + assist: Handler, + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) { check_with_config( TEST_CONFIG_IMPORT_ONE, assist, @@ -157,7 +175,10 @@ pub(crate) fn check_assist_not_applicable_for_import_one(assist: Handler, ra_fix /// Check assist in unresolved state. Useful to check assists for lazy computation. #[track_caller] -pub(crate) fn check_assist_unresolved(assist: Handler, ra_fixture: &str) { +pub(crate) fn check_assist_unresolved( + assist: Handler, + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) { check(assist, ra_fixture, ExpectedResult::Unresolved, None); } diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs index e20c4ef09e8..78ff4417913 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs @@ -246,7 +246,7 @@ pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize { } pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr { - invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr)) + invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr).into()) } fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { @@ -262,7 +262,7 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { T![>] => T![<=], T![>=] => T![<], // Parenthesize other expressions before prefixing `!` - _ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone()))), + _ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone())).into()), }; ted::replace(op_token, make::token(rev_token)); Some(bin.into()) diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs index 75caf6d49f7..7a9bdfe1ecc 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/gen_trait_fn_body.rs @@ -66,7 +66,7 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let pat = make::record_pat(variant_name.clone(), pats.into_iter()); let fields = make::record_expr_field_list(fields); let record_expr = make::record_expr(variant_name, fields).into(); - arms.push(make::match_arm(Some(pat.into()), None, record_expr)); + arms.push(make::match_arm(pat.into(), None, record_expr)); } // => match self { Self::Name(arg1) => Self::Name(arg1.clone()) } @@ -84,21 +84,21 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter()); let struct_name = make::expr_path(variant_name); let tuple_expr = make::expr_call(struct_name, make::arg_list(fields)); - arms.push(make::match_arm(Some(pat.into()), None, tuple_expr)); + arms.push(make::match_arm(pat.into(), None, tuple_expr)); } // => match self { Self::Name => Self::Name } None => { let pattern = make::path_pat(variant_name.clone()); let variant_expr = make::expr_path(variant_name); - arms.push(make::match_arm(Some(pattern), None, variant_expr)); + arms.push(make::match_arm(pattern, None, variant_expr)); } } } let match_target = make::expr_path(make::ext::ident_path("self")); let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - make::expr_match(match_target, list) + make::expr_match(match_target, list).into() } ast::Adt::Struct(strukt) => { match strukt.field_list() { @@ -190,7 +190,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { // => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(), let pat = make::record_pat(variant_name.clone(), pats.into_iter()); - arms.push(make::match_arm(Some(pat.into()), None, expr)); + arms.push(make::match_arm(pat.into(), None, expr)); } Some(ast::FieldList::TupleFieldList(list)) => { // => f.debug_tuple(name) @@ -223,7 +223,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { // => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(), let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter()); - arms.push(make::match_arm(Some(pat.into()), None, expr)); + arms.push(make::match_arm(pat.into(), None, expr)); } None => { let fmt_string = make::expr_literal(&(format!("\"{name}\""))).into(); @@ -232,7 +232,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let macro_call = make::expr_macro_call(macro_name, args); let variant_name = make::path_pat(variant_name); - arms.push(make::match_arm(Some(variant_name), None, macro_call)); + arms.push(make::match_arm(variant_name, None, macro_call)); } } } @@ -241,7 +241,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> { let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); let match_expr = make::expr_match(match_target, list); - let body = make::block_expr(None, Some(match_expr)); + let body = make::block_expr(None, Some(match_expr.into())); let body = body.indent(ast::edit::IndentLevel(1)); ted::replace(func.body()?.syntax(), body.clone_for_update().syntax()); Some(()) @@ -485,7 +485,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) - let tuple = make::tuple_pat(vec![left.into(), right.into()]); if let Some(expr) = expr { - arms.push(make::match_arm(Some(tuple.into()), None, expr)); + arms.push(make::match_arm(tuple.into(), None, expr)); } } @@ -518,7 +518,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) - let tuple = make::tuple_pat(vec![left.into(), right.into()]); if let Some(expr) = expr { - arms.push(make::match_arm(Some(tuple.into()), None, expr)); + arms.push(make::match_arm(tuple.into(), None, expr)); } } None => continue, @@ -538,12 +538,12 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) - } else { eq_check }; - arms.push(make::match_arm(Some(lhs), None, rhs)); + arms.push(make::match_arm(lhs, None, rhs)); } - let match_target = make::expr_tuple(vec![lhs_name, rhs_name]); + let match_target = make::expr_tuple([lhs_name, rhs_name]).into(); let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - make::expr_match(match_target, list) + make::expr_match(match_target, list).into() } }; @@ -599,15 +599,15 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) let variant_name = make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?); let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]); - arms.push(make::match_arm(Some(lhs.into()), None, make::expr_empty_block())); + arms.push(make::match_arm(lhs.into(), None, make::expr_empty_block().into())); arms.push(make::match_arm( - [make::ident_pat(false, false, make::name("ord")).into()], + make::ident_pat(false, false, make::name("ord")).into(), None, make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))), )); let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1)); - Some(make::expr_stmt(make::expr_match(match_target, list)).into()) + Some(make::expr_stmt(make::expr_match(match_target, list).into()).into()) } fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr { diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs index e95b291dd71..d434872ea59 100644 --- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs +++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/ref_field_expr.rs @@ -121,7 +121,7 @@ impl RefData { /// Derefs `expr` and wraps it in parens if necessary pub(crate) fn wrap_expr(&self, mut expr: ast::Expr) -> ast::Expr { if self.needs_deref { - expr = make::expr_prefix(T![*], expr); + expr = make::expr_prefix(T![*], expr).into(); } if self.needs_parentheses { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs index 414627fbaba..40669c65c57 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs @@ -329,7 +329,7 @@ impl Completions { ctx: &CompletionContext<'_>, dot_access: &DotAccess, func: hir::Function, - receiver: Option<hir::Name>, + receiver: Option<SmolStr>, local_name: Option<hir::Name>, ) { if !ctx.check_stability(Some(&func.attrs(ctx.db))) { @@ -475,7 +475,7 @@ impl Completions { &mut self, ctx: &CompletionContext<'_>, dot_access: &DotAccess, - receiver: Option<hir::Name>, + receiver: Option<SmolStr>, field: hir::Field, ty: &hir::Type, ) { @@ -533,7 +533,7 @@ impl Completions { pub(crate) fn add_tuple_field( &mut self, ctx: &CompletionContext<'_>, - receiver: Option<hir::Name>, + receiver: Option<SmolStr>, field: usize, ty: &hir::Type, ) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs index 26074672ba9..7679d9076de 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs @@ -2,7 +2,7 @@ use std::ops::ControlFlow; -use hir::{sym, HasContainer, ItemContainer, MethodCandidateCallback, Name}; +use hir::{HasContainer, ItemContainer, MethodCandidateCallback, Name}; use ide_db::FxHashSet; use syntax::SmolStr; @@ -25,21 +25,49 @@ pub(crate) fn complete_dot( _ => return, }; + let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. }); + let is_method_access_with_parens = + matches!(dot_access.kind, DotAccessKind::Method { has_parens: true }); + let traits_in_scope = ctx.traits_in_scope(); + // Suggest .await syntax for types that implement Future trait - if receiver_ty.impls_into_future(ctx.db) { + if let Some(future_output) = receiver_ty.into_future_output(ctx.db) { + let await_str = SmolStr::new_static("await"); let mut item = CompletionItem::new( CompletionItemKind::Keyword, ctx.source_range(), - SmolStr::new_static("await"), + await_str.clone(), ctx.edition, ); item.detail("expr.await"); item.add_to(acc, ctx.db); - } - let is_field_access = matches!(dot_access.kind, DotAccessKind::Field { .. }); - let is_method_access_with_parens = - matches!(dot_access.kind, DotAccessKind::Method { has_parens: true }); + // Completions that skip `.await`, e.g. `.await.foo()`. + let dot_access_kind = match &dot_access.kind { + DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => { + DotAccessKind::Field { receiver_is_ambiguous_float_literal: false } + } + it @ DotAccessKind::Method { .. } => *it, + }; + let dot_access = DotAccess { + receiver: dot_access.receiver.clone(), + receiver_ty: Some(hir::TypeInfo { original: future_output.clone(), adjusted: None }), + kind: dot_access_kind, + ctx: dot_access.ctx, + }; + complete_fields( + acc, + ctx, + &future_output, + |acc, field, ty| acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty), + |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty), + is_field_access, + is_method_access_with_parens, + ); + complete_methods(ctx, &future_output, &traits_in_scope, |func| { + acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None) + }); + } complete_fields( acc, @@ -50,8 +78,44 @@ pub(crate) fn complete_dot( is_field_access, is_method_access_with_parens, ); + complete_methods(ctx, receiver_ty, &traits_in_scope, |func| { + acc.add_method(ctx, dot_access, func, None, None) + }); - complete_methods(ctx, receiver_ty, |func| acc.add_method(ctx, dot_access, func, None, None)); + // FIXME: + // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute + // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`. + // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid + let iter = receiver_ty + .strip_references() + .add_reference(hir::Mutability::Shared) + .into_iterator_iter(ctx.db) + .map(|ty| (ty, SmolStr::new_static("iter()"))); + // Does <receiver_ty as IntoIterator>::IntoIter` exist? + let into_iter = || { + receiver_ty + .clone() + .into_iterator_iter(ctx.db) + .map(|ty| (ty, SmolStr::new_static("into_iter()"))) + }; + if let Some((iter, iter_sym)) = iter.or_else(into_iter) { + // Skip iterators, e.g. complete `.iter().filter_map()`. + let dot_access_kind = match &dot_access.kind { + DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => { + DotAccessKind::Field { receiver_is_ambiguous_float_literal: false } + } + it @ DotAccessKind::Method { .. } => *it, + }; + let dot_access = DotAccess { + receiver: dot_access.receiver.clone(), + receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }), + kind: dot_access_kind, + ctx: dot_access.ctx, + }; + complete_methods(ctx, &iter, &traits_in_scope, |func| { + acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None) + }); + } } pub(crate) fn complete_undotted_self( @@ -94,18 +158,16 @@ pub(crate) fn complete_undotted_self( in_breakable: expr_ctx.in_breakable, }, }, - Some(Name::new_symbol_root(sym::self_.clone())), + Some(SmolStr::new_static("self")), field, &ty, ) }, - |acc, field, ty| { - acc.add_tuple_field(ctx, Some(Name::new_symbol_root(sym::self_.clone())), field, &ty) - }, + |acc, field, ty| acc.add_tuple_field(ctx, Some(SmolStr::new_static("self")), field, &ty), true, false, ); - complete_methods(ctx, &ty, |func| { + complete_methods(ctx, &ty, &ctx.traits_in_scope(), |func| { acc.add_method( ctx, &DotAccess { @@ -118,7 +180,7 @@ pub(crate) fn complete_undotted_self( }, }, func, - Some(Name::new_symbol_root(sym::self_.clone())), + Some(SmolStr::new_static("self")), None, ) }); @@ -160,6 +222,7 @@ fn complete_fields( fn complete_methods( ctx: &CompletionContext<'_>, receiver: &hir::Type, + traits_in_scope: &FxHashSet<hir::TraitId>, f: impl FnMut(hir::Function), ) { struct Callback<'a, F> { @@ -205,7 +268,7 @@ fn complete_methods( receiver.iterate_method_candidates_split_inherent( ctx.db, &ctx.scope, - &ctx.traits_in_scope(), + traits_in_scope, Some(ctx.module), None, Callback { ctx, f, seen_methods: FxHashSet::default() }, @@ -214,25 +277,13 @@ fn complete_methods( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{ - check_edit, completion_list_no_kw, completion_list_no_kw_with_private_editable, - }; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual); - } - - fn check_with_private_editable(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw_with_private_editable(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::{check_edit, check_no_kw, check_with_private_editable}; #[test] fn test_struct_field_and_method_completion() { - check( + check_no_kw( r#" struct S { foo: u32 } impl S { @@ -249,7 +300,7 @@ fn foo(s: S) { s.$0 } #[test] fn no_unstable_method_on_stable() { - check( + check_no_kw( r#" //- /main.rs crate:main deps:std fn foo(s: std::S) { s.$0 } @@ -266,7 +317,7 @@ impl S { #[test] fn unstable_method_on_nightly() { - check( + check_no_kw( r#" //- toolchain:nightly //- /main.rs crate:main deps:std @@ -286,7 +337,7 @@ impl S { #[test] fn test_struct_field_completion_self() { - check( + check_no_kw( r#" struct S { the_field: (u32,) } impl S { @@ -302,7 +353,7 @@ impl S { #[test] fn test_struct_field_completion_autoderef() { - check( + check_no_kw( r#" struct A { the_field: (u32, i32) } impl A { @@ -318,7 +369,7 @@ impl A { #[test] fn test_no_struct_field_completion_for_method_call() { - check( + check_no_kw( r#" struct A { the_field: u32 } fn foo(a: A) { a.$0() } @@ -329,7 +380,7 @@ fn foo(a: A) { a.$0() } #[test] fn test_visibility_filtering() { - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:local pub mod m { @@ -348,7 +399,7 @@ fn foo(a: lib::m::A) { a.$0 } "#]], ); - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:library pub mod m { @@ -367,7 +418,7 @@ fn foo(a: lib::m::A) { a.$0 } "#]], ); - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:library pub mod m { @@ -384,7 +435,7 @@ fn foo(a: lib::m::A) { a.$0 } "#]], ); - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:local pub struct A {} @@ -402,7 +453,7 @@ fn foo(a: lib::A) { a.$0 } me pub_method() fn(&self) "#]], ); - check( + check_no_kw( r#" //- /lib.rs crate:lib new_source_root:library pub struct A {} @@ -524,7 +575,7 @@ fn foo(a: lib::A) { a.$0 } #[test] fn test_local_impls() { - check( + check_no_kw( r#" pub struct A {} mod m { @@ -553,7 +604,7 @@ fn foo(a: A) { #[test] fn test_doc_hidden_filtering() { - check( + check_no_kw( r#" //- /lib.rs crate:lib deps:dep fn foo(a: dep::A) { a.$0 } @@ -580,7 +631,7 @@ impl A { #[test] fn test_union_field_completion() { - check( + check_no_kw( r#" union U { field: u8, other: u16 } fn foo(u: U) { u.$0 } @@ -594,7 +645,7 @@ fn foo(u: U) { u.$0 } #[test] fn test_method_completion_only_fitting_impls() { - check( + check_no_kw( r#" struct A<T> {} impl A<u32> { @@ -613,7 +664,7 @@ fn foo(a: A<u32>) { a.$0 } #[test] fn test_trait_method_completion() { - check( + check_no_kw( r#" struct A {} trait Trait { fn the_method(&self); } @@ -643,7 +694,7 @@ fn foo(a: A) { a.the_method();$0 } #[test] fn test_trait_method_completion_deduplicated() { - check( + check_no_kw( r" struct A {} trait Trait { fn the_method(&self); } @@ -658,7 +709,7 @@ fn foo(a: &A) { a.$0 } #[test] fn completes_trait_method_from_other_module() { - check( + check_no_kw( r" struct A {} mod m { @@ -676,7 +727,7 @@ fn foo(a: A) { a.$0 } #[test] fn test_no_non_self_method() { - check( + check_no_kw( r#" struct A {} impl A { @@ -692,7 +743,7 @@ fn foo(a: A) { #[test] fn test_tuple_field_completion() { - check( + check_no_kw( r#" fn foo() { let b = (0, 3.14); @@ -708,7 +759,7 @@ fn foo() { #[test] fn test_tuple_struct_field_completion() { - check( + check_no_kw( r#" struct S(i32, f64); fn foo() { @@ -725,7 +776,7 @@ fn foo() { #[test] fn test_tuple_field_inference() { - check( + check_no_kw( r#" pub struct S; impl S { pub fn blah(&self) {} } @@ -747,7 +798,7 @@ impl T { #[test] fn test_field_no_same_name() { - check( + check_no_kw( r#" //- minicore: deref struct A { field: u8 } @@ -770,7 +821,7 @@ fn test(a: A) { #[test] fn test_tuple_field_no_same_index() { - check( + check_no_kw( r#" //- minicore: deref struct A(u8); @@ -793,7 +844,7 @@ fn test(a: A) { #[test] fn test_tuple_struct_deref_to_tuple_no_same_index() { - check( + check_no_kw( r#" //- minicore: deref struct A(u8); @@ -815,7 +866,7 @@ fn test(a: A) { #[test] fn test_completion_works_in_consts() { - check( + check_no_kw( r#" struct A { the_field: u32 } const X: u32 = { @@ -830,7 +881,7 @@ const X: u32 = { #[test] fn works_in_simple_macro_1() { - check( + check_no_kw( r#" macro_rules! m { ($e:expr) => { $e } } struct A { the_field: u32 } @@ -847,7 +898,7 @@ fn foo(a: A) { #[test] fn works_in_simple_macro_2() { // this doesn't work yet because the macro doesn't expand without the token -- maybe it can be fixed with better recovery - check( + check_no_kw( r#" macro_rules! m { ($e:expr) => { $e } } struct A { the_field: u32 } @@ -863,7 +914,7 @@ fn foo(a: A) { #[test] fn works_in_simple_macro_recursive_1() { - check( + check_no_kw( r#" macro_rules! m { ($e:expr) => { $e } } struct A { the_field: u32 } @@ -879,7 +930,7 @@ fn foo(a: A) { #[test] fn macro_expansion_resilient() { - check( + check_no_kw( r#" macro_rules! d { () => {}; @@ -905,7 +956,7 @@ fn foo(a: A) { #[test] fn test_method_completion_issue_3547() { - check( + check_no_kw( r#" struct HashSet<T> {} impl<T> HashSet<T> { @@ -924,7 +975,7 @@ fn foo() { #[test] fn completes_method_call_when_receiver_is_a_macro_call() { - check( + check_no_kw( r#" struct S; impl S { fn foo(&self) {} } @@ -939,7 +990,7 @@ fn main() { make_s!().f$0; } #[test] fn completes_after_macro_call_in_submodule() { - check( + check_no_kw( r#" macro_rules! empty { () => {}; @@ -967,7 +1018,7 @@ mod foo { #[test] fn issue_8931() { - check( + check_no_kw( r#" //- minicore: fn struct S; @@ -994,7 +1045,7 @@ impl S { #[test] fn completes_bare_fields_and_methods_in_methods() { - check( + check_no_kw( r#" struct Foo { field: i32 } @@ -1008,7 +1059,7 @@ impl Foo { fn foo(&self) { $0 } }"#, bt u32 u32 "#]], ); - check( + check_no_kw( r#" struct Foo(i32); @@ -1026,7 +1077,7 @@ impl Foo { fn foo(&mut self) { $0 } }"#, #[test] fn macro_completion_after_dot() { - check( + check_no_kw( r#" macro_rules! m { ($e:expr) => { $e }; @@ -1051,7 +1102,7 @@ fn f() { #[test] fn completes_method_call_when_receiver_type_has_errors_issue_10297() { - check( + check_no_kw( r#" //- minicore: iterator, sized struct Vec<T>; @@ -1102,7 +1153,7 @@ fn main() { #[test] fn issue_12484() { - check( + check_no_kw( r#" //- minicore: sized trait SizeUser { @@ -1124,7 +1175,7 @@ fn test(thing: impl Encrypt) { #[test] fn only_consider_same_type_once() { - check( + check_no_kw( r#" //- minicore: deref struct A(u8); @@ -1150,7 +1201,7 @@ fn test(a: A) { #[test] fn no_inference_var_in_completion() { - check( + check_no_kw( r#" struct S<T>(T); fn test(s: S<Unknown>) { @@ -1165,7 +1216,7 @@ fn test(s: S<Unknown>) { #[test] fn assoc_impl_1() { - check( + check_no_kw( r#" //- minicore: deref fn main() { @@ -1206,7 +1257,7 @@ impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> { #[test] fn assoc_impl_2() { - check( + check_no_kw( r#" //- minicore: deref fn main() { @@ -1242,7 +1293,7 @@ impl<B: Bar, F: core::ops::Deref<Target = B>> Foo<F> { #[test] fn test_struct_function_field_completion() { - check( + check_no_kw( r#" struct S { va_field: u32, fn_field: fn() } fn foo() { S { va_field: 0, fn_field: || {} }.fi$0() } @@ -1267,7 +1318,7 @@ fn foo() { (S { va_field: 0, fn_field: || {} }.fn_field)() } #[test] fn test_tuple_function_field_completion() { - check( + check_no_kw( r#" struct B(u32, fn()) fn foo() { @@ -1301,7 +1352,7 @@ fn foo() { #[test] fn test_fn_field_dot_access_method_has_parens_false() { - check( + check_no_kw( r#" struct Foo { baz: fn() } impl Foo { @@ -1318,4 +1369,101 @@ fn baz() { "#]], ); } + + #[test] + fn skip_iter() { + check_no_kw( + r#" + //- minicore: iterator + fn foo() { + [].$0 + } + "#, + expect![[r#" + me clone() (as Clone) fn(&self) -> Self + me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter + "#]], + ); + check_no_kw( + r#" +//- minicore: iterator +struct MyIntoIter; +impl IntoIterator for MyIntoIter { + type Item = (); + type IntoIter = MyIterator; + fn into_iter(self) -> Self::IntoIter { + MyIterator + } +} + +struct MyIterator; +impl Iterator for MyIterator { + type Item = (); + fn next(&mut self) -> Self::Item {} +} + +fn foo() { + MyIntoIter.$0 +} +"#, + expect![[r#" + me into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter + me into_iter().by_ref() (as Iterator) fn(&mut self) -> &mut Self + me into_iter().into_iter() (as IntoIterator) fn(self) -> <Self as IntoIterator>::IntoIter + me into_iter().next() (as Iterator) fn(&mut self) -> Option<<Self as Iterator>::Item> + me into_iter().nth(…) (as Iterator) fn(&mut self, usize) -> Option<<Self as Iterator>::Item> + "#]], + ); + } + + #[test] + fn skip_await() { + check_no_kw( + r#" +//- minicore: future +struct Foo; +impl Foo { + fn foo(self) {} +} + +async fn foo() -> Foo { Foo } + +async fn bar() { + foo().$0 +} +"#, + expect![[r#" + me await.foo() fn(self) + me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture +"#]], + ); + check_edit( + "foo", + r#" +//- minicore: future +struct Foo; +impl Foo { + fn foo(self) {} +} + +async fn foo() -> Foo { Foo } + +async fn bar() { + foo().$0 +} +"#, + r#" +struct Foo; +impl Foo { + fn foo(self) {} +} + +async fn foo() -> Foo { Foo } + +async fn bar() { + foo().await.foo();$0 +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs index 0b6790d42a6..40af5203e9c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/env_vars.rs @@ -68,43 +68,40 @@ pub(crate) fn complete_cargo_env_vars( mod tests { use crate::tests::{check_edit, completion_list}; - fn check(macro_name: &str) { + #[test] + fn completes_env_variable_in_env() { check_edit( "CARGO_BIN_NAME", - &format!( - r#" - #[rustc_builtin_macro] - macro {macro_name} {{ - ($var:literal) => {{ 0 }} - }} - - fn main() {{ - let foo = {macro_name}!("CAR$0"); - }} - "# - ), - &format!( - r#" - #[rustc_builtin_macro] - macro {macro_name} {{ - ($var:literal) => {{ 0 }} - }} - - fn main() {{ - let foo = {macro_name}!("CARGO_BIN_NAME"); - }} - "# - ), + r#" +//- minicore: env +fn main() { + let foo = env!("CAR$0"); +} + "#, + r#" +fn main() { + let foo = env!("CARGO_BIN_NAME"); +} + "#, ); } - #[test] - fn completes_env_variable_in_env() { - check("env") - } #[test] fn completes_env_variable_in_option_env() { - check("option_env"); + check_edit( + "CARGO_BIN_NAME", + r#" +//- minicore: env +fn main() { + let foo = option_env!("CAR$0"); +} + "#, + r#" +fn main() { + let foo = option_env!("CARGO_BIN_NAME"); +} + "#, + ); } #[test] diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs index c2e5eefe101..db18b531d7c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs @@ -62,6 +62,7 @@ pub(crate) fn complete_expr_path( in_condition, incomplete_let, ref ref_expr_parent, + after_amp, ref is_func_update, ref innermost_ret_ty, ref impl_, @@ -69,8 +70,23 @@ pub(crate) fn complete_expr_path( .. } = expr_ctx; - let wants_mut_token = - ref_expr_parent.as_ref().map(|it| it.mut_token().is_none()).unwrap_or(false); + let (has_raw_token, has_const_token, has_mut_token) = ref_expr_parent + .as_ref() + .map(|it| (it.raw_token().is_some(), it.const_token().is_some(), it.mut_token().is_some())) + .unwrap_or((false, false, false)); + + let wants_raw_token = ref_expr_parent.is_some() && !has_raw_token && after_amp; + let wants_const_token = + ref_expr_parent.is_some() && has_raw_token && !has_const_token && !has_mut_token; + let wants_mut_token = if ref_expr_parent.is_some() { + if has_raw_token { + !has_const_token && !has_mut_token + } else { + !has_mut_token + } + } else { + false + }; let scope_def_applicable = |def| match def { ScopeDef::GenericParam(hir::GenericParam::LifetimeParam(_)) | ScopeDef::Label(_) => false, @@ -354,6 +370,12 @@ pub(crate) fn complete_expr_path( add_keyword("else if", "else if $1 {\n $0\n}"); } + if wants_raw_token { + add_keyword("raw", "raw "); + } + if wants_const_token { + add_keyword("const", "const "); + } if wants_mut_token { add_keyword("mut", "mut "); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs index bcfda928c4d..7c2cc2a6c1d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_abi.rs @@ -65,18 +65,13 @@ pub(crate) fn complete_extern_abi( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::{check_edit, check_no_kw}; #[test] fn only_completes_in_string_literals() { - check( + check_no_kw( r#" $0 fn foo {} "#, @@ -86,7 +81,7 @@ $0 fn foo {} #[test] fn requires_extern_prefix() { - check( + check_no_kw( r#" "$0" fn foo {} "#, @@ -96,7 +91,7 @@ $0 fn foo {} #[test] fn works() { - check( + check_no_kw( r#" extern "$0" fn foo {} "#, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs index 3b2b2fd706e..73313eeaa6b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs @@ -5,7 +5,7 @@ use ide_db::imports::{ insert_use::ImportScope, }; use itertools::Itertools; -use syntax::{ast, AstNode, SyntaxNode, ToSmolStr, T}; +use syntax::{ast, AstNode, SyntaxNode, ToSmolStr}; use crate::{ config::AutoImportExclusionType, @@ -403,10 +403,11 @@ fn import_on_the_fly_method( fn import_name(ctx: &CompletionContext<'_>) -> String { let token_kind = ctx.token.kind(); - if matches!(token_kind, T![.] | T![::]) { - String::new() - } else { + + if token_kind.is_any_identifier() { ctx.token.to_string() + } else { + String::new() } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs index a87c60c694a..dcd40c3412c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/format_string.rs @@ -61,18 +61,13 @@ pub(crate) fn format_string( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::{check_edit, check_no_kw}; #[test] fn works_when_wrapped() { - check( + check_no_kw( r#" //- minicore: fmt macro_rules! print { @@ -89,7 +84,7 @@ fn main() { #[test] fn no_completion_without_brace() { - check( + check_no_kw( r#" //- minicore: fmt fn main() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs index 80d72b460f9..6d1945c4534 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -514,18 +514,13 @@ fn function_declaration( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list_no_kw}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual) - } + use crate::tests::{check_edit, check_no_kw}; #[test] fn no_completion_inside_fn() { - check( + check_no_kw( r" trait Test { fn test(); fn test2(); } struct T; @@ -544,7 +539,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { fn test(); fn test2(); } struct T; @@ -558,7 +553,7 @@ impl Test for T { expect![[""]], ); - check( + check_no_kw( r" trait Test { fn test(); fn test2(); } struct T; @@ -573,7 +568,7 @@ impl Test for T { ); // https://github.com/rust-lang/rust-analyzer/pull/5976#issuecomment-692332191 - check( + check_no_kw( r" trait Test { fn test(); fn test2(); } struct T; @@ -587,7 +582,7 @@ impl Test for T { expect![[r#""#]], ); - check( + check_no_kw( r" trait Test { fn test(_: i32); fn test2(); } struct T; @@ -606,7 +601,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { fn test(_: fn()); fn test2(); } struct T; @@ -624,7 +619,7 @@ impl Test for T { #[test] fn no_completion_inside_const() { - check( + check_no_kw( r" trait Test { const TEST: fn(); const TEST2: u32; type Test; fn test(); } struct T; @@ -636,7 +631,7 @@ impl Test for T { expect![[r#""#]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -653,7 +648,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -670,7 +665,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -689,7 +684,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -703,7 +698,7 @@ impl Test for T { expect![[""]], ); - check( + check_no_kw( r" trait Test { const TEST: u32; const TEST2: u32; type Test; fn test(); } struct T; @@ -720,7 +715,7 @@ impl Test for T { #[test] fn no_completion_inside_type() { - check( + check_no_kw( r" trait Test { type Test; type Test2; fn test(); } struct T; @@ -737,7 +732,7 @@ impl Test for T { "#]], ); - check( + check_no_kw( r" trait Test { type Test; type Test2; fn test(); } struct T; @@ -1263,7 +1258,7 @@ impl Foo<u32> for Bar { #[test] fn works_directly_in_impl() { - check( + check_no_kw( r#" trait Tr { fn required(); @@ -1277,7 +1272,7 @@ impl Tr for () { fn fn required() "#]], ); - check( + check_no_kw( r#" trait Tr { fn provided() {} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs index 4700ed6c1ae..6541ee502d8 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs @@ -32,14 +32,9 @@ pub(crate) fn complete_for_and_where( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) - } + use crate::tests::{check, check_edit}; #[test] fn test_else_edit_after_if() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs index 0692446381b..53a62fe49c5 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/lifetime.rs @@ -59,14 +59,9 @@ pub(crate) fn complete_label( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::{check_edit, completion_list}; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::{check, check_edit}; #[test] fn check_lifetime_edit() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs index f12f011a6bd..bafe3294209 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs @@ -159,14 +159,9 @@ fn module_chain_to_containing_module_file( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; - use crate::tests::completion_list; - - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } + use crate::tests::check; #[test] fn lib_module_completion() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs index 7b57eea0524..67ea05e002b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs @@ -303,7 +303,7 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) { resulting_element = ast::Expr::from(parent_deref_element); - new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt); + new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt).into(); } if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) { @@ -401,18 +401,13 @@ fn add_custom_postfix_completions( #[cfg(test)] mod tests { - use expect_test::{expect, Expect}; + use expect_test::expect; use crate::{ - tests::{check_edit, check_edit_with_config, completion_list, TEST_CONFIG}, + tests::{check, check_edit, check_edit_with_config, TEST_CONFIG}, CompletionConfig, Snippet, }; - fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) - } - #[test] fn postfix_completion_works_for_trivial_path_expression() { check( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs index 3705e2c73d6..3a2a4a23a19 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs @@ -146,6 +146,7 @@ pub(crate) struct PathExprCtx { pub(crate) in_condition: bool, pub(crate) incomplete_let: bool, pub(crate) ref_expr_parent: Option<ast::RefExpr>, + pub(crate) after_amp: bool, /// The surrounding RecordExpression we are completing a functional update pub(crate) is_func_update: Option<ast::RecordExpr>, pub(crate) self_param: Option<hir::SelfParam>, @@ -390,7 +391,7 @@ pub(crate) struct DotAccess { pub(crate) ctx: DotAccessExprCtx, } -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub(crate) enum DotAccessKind { Field { /// True if the receiver is an integer and there is no ident in the original file after it yet @@ -402,7 +403,7 @@ pub(crate) enum DotAccessKind { }, } -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub(crate) struct DotAccessExprCtx { pub(crate) in_block_expr: bool, pub(crate) in_breakable: BreakableKind, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs index acce62a041c..3c4d489c0ff 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs @@ -123,10 +123,11 @@ fn expand( ) -> Option<ExpansionResult> { let _p = tracing::info_span!("CompletionContext::expand").entered(); + // Left biased since there may already be an identifier token there, and we appended to it. if !sema.might_be_inside_macro_call(&fake_ident_token) && original_file .token_at_offset(original_offset + relative_offset) - .right_biased() + .left_biased() .is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token)) { // Recursion base case. @@ -1150,6 +1151,9 @@ fn classify_name_ref( let after_if_expr = after_if_expr(it.clone()); let ref_expr_parent = path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast); + let after_amp = non_trivia_sibling(it.clone().into(), Direction::Prev) + .map(|it| it.kind() == SyntaxKind::AMP) + .unwrap_or(false); let (innermost_ret_ty, self_param) = { let find_ret_ty = |it: SyntaxNode| { if let Some(item) = ast::Item::cast(it.clone()) { @@ -1219,6 +1223,7 @@ fn classify_name_ref( after_if_expr, in_condition, ref_expr_parent, + after_amp, is_func_update, innermost_ret_ty, self_param, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs index 82a1c10c531..fc2bfc01e62 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/tests.rs @@ -6,7 +6,7 @@ use crate::{ tests::{position, TEST_CONFIG}, }; -fn check_expected_type_and_name(ra_fixture: &str, expect: Expect) { +fn check_expected_type_and_name(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, pos) = position(ra_fixture); let config = TEST_CONFIG; let (completion_context, _analysis) = CompletionContext::new(&db, pos, &config).unwrap(); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs index b91f915619d..dc2f9a76802 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs @@ -79,7 +79,7 @@ pub struct CompletionItem { // FIXME: We shouldn't expose Mutability here (that is HIR types at all), its fine for now though // until we have more splitting completions in which case we should think about // generalizing this. See https://github.com/rust-lang/rust-analyzer/issues/12571 - pub ref_match: Option<(Mutability, TextSize)>, + pub ref_match: Option<(CompletionItemRefMode, TextSize)>, /// The import data to add to completion's edits. /// (ImportPath, LastSegment) @@ -128,8 +128,15 @@ impl fmt::Debug for CompletionItem { s.field("relevance", &self.relevance); } - if let Some((mutability, offset)) = &self.ref_match { - s.field("ref_match", &format!("&{}@{offset:?}", mutability.as_keyword_for_ref())); + if let Some((ref_mode, offset)) = self.ref_match { + let prefix = match ref_mode { + CompletionItemRefMode::Reference(mutability) => match mutability { + Mutability::Shared => "&", + Mutability::Mut => "&mut ", + }, + CompletionItemRefMode::Dereference => "*", + }; + s.field("ref_match", &format!("{}@{offset:?}", prefix)); } if self.trigger_call_info { s.field("trigger_call_info", &true); @@ -400,6 +407,12 @@ impl CompletionItemKind { } } +#[derive(Copy, Clone, Debug)] +pub enum CompletionItemRefMode { + Reference(Mutability), + Dereference, +} + impl CompletionItem { pub(crate) fn new( kind: impl Into<CompletionItemKind>, @@ -441,15 +454,14 @@ impl CompletionItem { let mut relevance = self.relevance; relevance.type_match = Some(CompletionRelevanceTypeMatch::Exact); - self.ref_match.map(|(mutability, offset)| { - ( - format!("&{}{}", mutability.as_keyword_for_ref(), self.label.primary), - ide_db::text_edit::Indel::insert( - offset, - format!("&{}", mutability.as_keyword_for_ref()), - ), - relevance, - ) + self.ref_match.map(|(mode, offset)| { + let prefix = match mode { + CompletionItemRefMode::Reference(Mutability::Shared) => "&", + CompletionItemRefMode::Reference(Mutability::Mut) => "&mut ", + CompletionItemRefMode::Dereference => "*", + }; + let label = format!("{prefix}{}", self.label.primary); + (label, ide_db::text_edit::Indel::insert(offset, String::from(prefix)), relevance) }) } } @@ -473,7 +485,7 @@ pub(crate) struct Builder { deprecated: bool, trigger_call_info: bool, relevance: CompletionRelevance, - ref_match: Option<(Mutability, TextSize)>, + ref_match: Option<(CompletionItemRefMode, TextSize)>, edition: Edition, } @@ -657,8 +669,12 @@ impl Builder { self.imports_to_add.push(import_to_add); self } - pub(crate) fn ref_match(&mut self, mutability: Mutability, offset: TextSize) -> &mut Builder { - self.ref_match = Some((mutability, offset)); + pub(crate) fn ref_match( + &mut self, + ref_mode: CompletionItemRefMode, + offset: TextSize, + ) -> &mut Builder { + self.ref_match = Some((ref_mode, offset)); self } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs index ca6c9ad9f08..56d7eeaf8ea 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs @@ -33,8 +33,9 @@ use crate::{ pub use crate::{ config::{AutoImportExclusionType, CallableSnippets, CompletionConfig}, item::{ - CompletionItem, CompletionItemKind, CompletionRelevance, CompletionRelevancePostfixMatch, - CompletionRelevanceReturnType, CompletionRelevanceTypeMatch, + CompletionItem, CompletionItemKind, CompletionItemRefMode, CompletionRelevance, + CompletionRelevancePostfixMatch, CompletionRelevanceReturnType, + CompletionRelevanceTypeMatch, }, snippet::{Snippet, SnippetScope}, }; diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs index c239ca512da..61e8114d381 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs @@ -18,7 +18,7 @@ use ide_db::{ imports::import_assets::LocatedImport, RootDatabase, SnippetCap, SymbolKind, }; -use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, TextRange, ToSmolStr}; +use syntax::{ast, format_smolstr, AstNode, SmolStr, SyntaxKind, TextRange, ToSmolStr}; use crate::{ context::{DotAccess, DotAccessKind, PathCompletionCtx, PathKind, PatternContext}, @@ -28,7 +28,8 @@ use crate::{ literal::render_variant_lit, macro_::{render_macro, render_macro_pat}, }, - CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance, + CompletionContext, CompletionItem, CompletionItemKind, CompletionItemRefMode, + CompletionRelevance, }; /// Interface for data and methods required for items rendering. #[derive(Debug, Clone)] @@ -122,7 +123,7 @@ impl<'a> RenderContext<'a> { pub(crate) fn render_field( ctx: RenderContext<'_>, dot_access: &DotAccess, - receiver: Option<hir::Name>, + receiver: Option<SmolStr>, field: hir::Field, ty: &hir::Type, ) -> CompletionItem { @@ -136,7 +137,7 @@ pub(crate) fn render_field( let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), - field_with_receiver(db, receiver.as_ref(), &name, ctx.completion.edition), + field_with_receiver(receiver.as_deref(), &name), ctx.completion.edition, ); item.set_relevance(CompletionRelevance { @@ -158,8 +159,7 @@ pub(crate) fn render_field( builder.replace( ctx.source_range(), - field_with_receiver(db, receiver.as_ref(), &escaped_name, ctx.completion.edition) - .into(), + field_with_receiver(receiver.as_deref(), &escaped_name).into(), ); let expected_fn_type = @@ -183,17 +183,12 @@ pub(crate) fn render_field( item.text_edit(builder.finish()); } else { - item.insert_text(field_with_receiver( - db, - receiver.as_ref(), - &escaped_name, - ctx.completion.edition, - )); + item.insert_text(field_with_receiver(receiver.as_deref(), &escaped_name)); } if let Some(receiver) = &dot_access.receiver { if let Some(original) = ctx.completion.sema.original_ast_node(receiver.clone()) { - if let Some(ref_match) = compute_ref_match(ctx.completion, ty) { - item.ref_match(ref_match, original.syntax().text_range().start()); + if let Some(ref_mode) = compute_ref_match(ctx.completion, ty) { + item.ref_match(ref_mode, original.syntax().text_range().start()); } } } @@ -201,33 +196,21 @@ pub(crate) fn render_field( item.build(db) } -fn field_with_receiver( - db: &RootDatabase, - receiver: Option<&hir::Name>, - field_name: &str, - edition: Edition, -) -> SmolStr { - receiver.map_or_else( - || field_name.into(), - |receiver| format_smolstr!("{}.{field_name}", receiver.display(db, edition)), - ) +fn field_with_receiver(receiver: Option<&str>, field_name: &str) -> SmolStr { + receiver + .map_or_else(|| field_name.into(), |receiver| format_smolstr!("{}.{field_name}", receiver)) } pub(crate) fn render_tuple_field( ctx: RenderContext<'_>, - receiver: Option<hir::Name>, + receiver: Option<SmolStr>, field: usize, ty: &hir::Type, ) -> CompletionItem { let mut item = CompletionItem::new( SymbolKind::Field, ctx.source_range(), - field_with_receiver( - ctx.db(), - receiver.as_ref(), - &field.to_string(), - ctx.completion.edition, - ), + field_with_receiver(receiver.as_deref(), &field.to_string()), ctx.completion.edition, ); item.detail(ty.display(ctx.db(), ctx.completion.edition).to_string()) @@ -440,7 +423,7 @@ fn render_resolution_path( let name = local_name.display_no_db(ctx.completion.edition).to_smolstr(); let mut item = render_resolution_simple_(ctx, &local_name, import_to_add, resolution); - if local_name.is_escaped(completion.edition) { + if local_name.needs_escape(completion.edition) { item.insert_text(local_name.display_no_db(completion.edition).to_smolstr()); } // Add `<>` for generic types @@ -638,20 +621,34 @@ fn compute_exact_name_match(ctx: &CompletionContext<'_>, completion_name: &str) fn compute_ref_match( ctx: &CompletionContext<'_>, completion_ty: &hir::Type, -) -> Option<hir::Mutability> { +) -> Option<CompletionItemRefMode> { let expected_type = ctx.expected_type.as_ref()?; - if completion_ty != expected_type { - let expected_type_without_ref = expected_type.remove_ref()?; - if completion_ty.autoderef(ctx.db).any(|deref_ty| deref_ty == expected_type_without_ref) { + let expected_without_ref = expected_type.remove_ref(); + let completion_without_ref = completion_ty.remove_ref(); + + if completion_ty == expected_type { + return None; + } + + if let Some(expected_without_ref) = &expected_without_ref { + if completion_ty.autoderef(ctx.db).any(|ty| ty == *expected_without_ref) { cov_mark::hit!(suggest_ref); let mutability = if expected_type.is_mutable_reference() { hir::Mutability::Mut } else { hir::Mutability::Shared }; - return Some(mutability); - }; + return Some(CompletionItemRefMode::Reference(mutability)); + } + } + + if let Some(completion_without_ref) = completion_without_ref { + if completion_without_ref == *expected_type && completion_without_ref.is_copy(ctx.db) { + cov_mark::hit!(suggest_deref); + return Some(CompletionItemRefMode::Dereference); + } } + None } @@ -664,16 +661,16 @@ fn path_ref_match( if let Some(original_path) = &path_ctx.original_path { // At least one char was typed by the user already, in that case look for the original path if let Some(original_path) = completion.sema.original_ast_node(original_path.clone()) { - if let Some(ref_match) = compute_ref_match(completion, ty) { - item.ref_match(ref_match, original_path.syntax().text_range().start()); + if let Some(ref_mode) = compute_ref_match(completion, ty) { + item.ref_match(ref_mode, original_path.syntax().text_range().start()); } } } else { // completion requested on an empty identifier, there is no path here yet. // FIXME: This might create inconsistent completions where we show a ref match in macro inputs // as long as nothing was typed yet - if let Some(ref_match) = compute_ref_match(completion, ty) { - item.ref_match(ref_match, completion.position.offset); + if let Some(ref_mode) = compute_ref_match(completion, ty) { + item.ref_match(ref_mode, completion.position.offset); } } } @@ -693,20 +690,28 @@ mod tests { }; #[track_caller] - fn check(ra_fixture: &str, kind: impl Into<CompletionItemKind>, expect: Expect) { + fn check( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + kind: impl Into<CompletionItemKind>, + expect: Expect, + ) { let actual = do_completion(ra_fixture, kind.into()); expect.assert_debug_eq(&actual); } #[track_caller] - fn check_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) { + fn check_kinds( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + kinds: &[CompletionItemKind], + expect: Expect, + ) { let actual: Vec<_> = kinds.iter().flat_map(|&kind| do_completion(ra_fixture, kind)).collect(); expect.assert_debug_eq(&actual); } #[track_caller] - fn check_function_relevance(ra_fixture: &str, expect: Expect) { + fn check_function_relevance(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let actual: Vec<_> = do_completion(ra_fixture, CompletionItemKind::SymbolKind(SymbolKind::Method)) .into_iter() @@ -717,7 +722,11 @@ mod tests { } #[track_caller] - fn check_relevance_for_kinds(ra_fixture: &str, kinds: &[CompletionItemKind], expect: Expect) { + fn check_relevance_for_kinds( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + kinds: &[CompletionItemKind], + expect: Expect, + ) { let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None); actual.retain(|it| kinds.contains(&it.kind)); actual.sort_by_key(|it| cmp::Reverse(it.relevance.score())); @@ -725,7 +734,7 @@ mod tests { } #[track_caller] - fn check_relevance(ra_fixture: &str, expect: Expect) { + fn check_relevance(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let mut actual = get_all_items(TEST_CONFIG, ra_fixture, None); actual.retain(|it| it.kind != CompletionItemKind::Snippet); actual.retain(|it| it.kind != CompletionItemKind::Keyword); @@ -2053,7 +2062,42 @@ fn main() { } #[test] - fn suggest_deref() { + fn suggest_deref_copy() { + cov_mark::check!(suggest_deref); + check_relevance( + r#" +//- minicore: copy +struct Foo; + +impl Copy for Foo {} +impl Clone for Foo { + fn clone(&self) -> Self { *self } +} + +fn bar(x: Foo) {} + +fn main() { + let foo = &Foo; + bar($0); +} +"#, + expect![[r#" + st Foo Foo [type] + st Foo Foo [type] + ex Foo [type] + lc foo &Foo [local] + lc *foo [type+local] + fn bar(…) fn(Foo) [] + fn main() fn() [] + md core [] + tt Clone [] + tt Copy [] + "#]], + ); + } + + #[test] + fn suggest_deref_trait() { check_relevance( r#" //- minicore: deref diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs index a859d79e243..3b97d67169e 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs @@ -23,7 +23,7 @@ use crate::{ #[derive(Debug)] enum FuncKind<'ctx> { Function(&'ctx PathCompletionCtx), - Method(&'ctx DotAccess, Option<hir::Name>), + Method(&'ctx DotAccess, Option<SmolStr>), } pub(crate) fn render_fn( @@ -39,7 +39,7 @@ pub(crate) fn render_fn( pub(crate) fn render_method( ctx: RenderContext<'_>, dot_access: &DotAccess, - receiver: Option<hir::Name>, + receiver: Option<SmolStr>, local_name: Option<hir::Name>, func: hir::Function, ) -> Builder { @@ -59,16 +59,8 @@ fn render( let (call, escaped_call) = match &func_kind { FuncKind::Method(_, Some(receiver)) => ( - format_smolstr!( - "{}.{}", - receiver.unescaped().display(ctx.db()), - name.unescaped().display(ctx.db()) - ), - format_smolstr!( - "{}.{}", - receiver.display(ctx.db(), completion.edition), - name.display(ctx.db(), completion.edition) - ), + format_smolstr!("{}.{}", receiver, name.unescaped().display(ctx.db())), + format_smolstr!("{}.{}", receiver, name.display(ctx.db(), completion.edition)), ), _ => ( name.unescaped().display(db).to_smolstr(), @@ -143,8 +135,8 @@ fn render( } FuncKind::Method(DotAccess { receiver: Some(receiver), .. }, _) => { if let Some(original_expr) = completion.sema.original_ast_node(receiver.clone()) { - if let Some(ref_match) = compute_ref_match(completion, &ret_type) { - item.ref_match(ref_match, original_expr.syntax().text_range().start()); + if let Some(ref_mode) = compute_ref_match(completion, &ret_type) { + item.ref_match(ref_mode, original_expr.syntax().text_range().start()); } } } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs index 1815f340532..b7dbf0a6306 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs @@ -89,22 +89,24 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig { exclude_traits: &[], }; -pub(crate) fn completion_list(ra_fixture: &str) -> String { +pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { completion_list_with_config(TEST_CONFIG, ra_fixture, true, None) } -pub(crate) fn completion_list_no_kw(ra_fixture: &str) -> String { +pub(crate) fn completion_list_no_kw(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String { completion_list_with_config(TEST_CONFIG, ra_fixture, false, None) } -pub(crate) fn completion_list_no_kw_with_private_editable(ra_fixture: &str) -> String { +pub(crate) fn completion_list_no_kw_with_private_editable( + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) -> String { let mut config = TEST_CONFIG; config.enable_private_editable = true; completion_list_with_config(config, ra_fixture, false, None) } pub(crate) fn completion_list_with_trigger_character( - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, trigger_character: Option<char>, ) -> String { completion_list_with_config(TEST_CONFIG, ra_fixture, true, trigger_character) @@ -112,7 +114,7 @@ pub(crate) fn completion_list_with_trigger_character( fn completion_list_with_config_raw( config: CompletionConfig<'_>, - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, include_keywords: bool, trigger_character: Option<char>, ) -> Vec<CompletionItem> { @@ -135,7 +137,7 @@ fn completion_list_with_config_raw( fn completion_list_with_config( config: CompletionConfig<'_>, - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, include_keywords: bool, trigger_character: Option<char>, ) -> String { @@ -148,7 +150,9 @@ fn completion_list_with_config( } /// Creates analysis from a multi-file fixture, returns positions marked with $0. -pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { +pub(crate) fn position( + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) -> (RootDatabase, FilePosition) { let change_fixture = ChangeFixture::parse(ra_fixture); let mut database = RootDatabase::default(); database.enable_proc_attr_macros(); @@ -216,7 +220,11 @@ fn render_completion_list(completions: Vec<CompletionItem>) -> String { } #[track_caller] -pub(crate) fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) { +pub(crate) fn check_edit( + what: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { check_edit_with_config(TEST_CONFIG, what, ra_fixture_before, ra_fixture_after) } @@ -253,11 +261,40 @@ pub(crate) fn check_edit_with_config( assert_eq_text!(&ra_fixture_after, &actual) } -fn check_empty(ra_fixture: &str, expect: Expect) { +pub(crate) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let actual = completion_list(ra_fixture); expect.assert_eq(&actual); } +pub(crate) fn check_with_base_items( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, +) { + check(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"), expect) +} + +pub(crate) fn check_no_kw(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { + let actual = completion_list_no_kw(ra_fixture); + expect.assert_eq(&actual) +} + +pub(crate) fn check_with_private_editable( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, +) { + let actual = completion_list_no_kw_with_private_editable(ra_fixture); + expect.assert_eq(&actual); +} + +pub(crate) fn check_with_trigger_character( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + trigger_character: Option<char>, + expect: Expect, +) { + let actual = completion_list_with_trigger_character(ra_fixture, trigger_character); + expect.assert_eq(&actual) +} + pub(crate) fn get_all_items( config: CompletionConfig<'_>, code: &str, diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs index ebf35820570..32d3b50f237 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/attribute.rs @@ -1,12 +1,7 @@ //! Completion tests for attributes. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_edit, completion_list}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} +use crate::tests::{check, check_edit}; #[test] fn derive_helpers() { @@ -788,14 +783,9 @@ mod cfg { mod derive { use super::*; - fn check_derive(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } - #[test] fn no_completion_for_incorrect_derive() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive{$0)] struct Test; @@ -806,7 +796,7 @@ mod derive { #[test] fn empty_derive() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive($0)] struct Test; @@ -828,7 +818,7 @@ mod derive { #[test] fn derive_with_input_before() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive(serde::Serialize, PartialEq, $0)] struct Test; @@ -849,7 +839,7 @@ mod derive { #[test] fn derive_with_input_after() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive($0 serde::Serialize, PartialEq)] struct Test; @@ -870,7 +860,7 @@ mod derive { #[test] fn derive_with_existing_derives() { - check_derive( + check( r#" //- minicore: derive, copy, clone, ord, eq, default, fmt #[derive(PartialEq, Eq, Or$0)] struct Test; @@ -890,7 +880,7 @@ mod derive { #[test] fn derive_flyimport() { - check_derive( + check( r#" //- proc_macros: derive_identity //- minicore: derive @@ -904,7 +894,7 @@ mod derive { kw self:: "#]], ); - check_derive( + check( r#" //- proc_macros: derive_identity //- minicore: derive @@ -940,7 +930,7 @@ use proc_macros::DeriveIdentity; #[test] fn qualified() { - check_derive( + check( r#" //- proc_macros: derive_identity //- minicore: derive, copy, clone @@ -950,7 +940,7 @@ use proc_macros::DeriveIdentity; de DeriveIdentity proc_macro DeriveIdentity "#]], ); - check_derive( + check( r#" //- proc_macros: derive_identity //- minicore: derive, copy, clone @@ -1056,19 +1046,14 @@ mod lint { mod repr { use super::*; - fn check_repr(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); - } - #[test] fn no_completion_for_incorrect_repr() { - check_repr(r#"#[repr{$0)] struct Test;"#, expect![[]]) + check(r#"#[repr{$0)] struct Test;"#, expect![[]]) } #[test] fn empty() { - check_repr( + check( r#"#[repr($0)] struct Test;"#, expect![[r#" ba C @@ -1093,12 +1078,12 @@ mod repr { #[test] fn transparent() { - check_repr(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]); + check(r#"#[repr(transparent, $0)] struct Test;"#, expect![[r#""#]]); } #[test] fn align() { - check_repr( + check( r#"#[repr(align(1), $0)] struct Test;"#, expect![[r#" ba C @@ -1121,7 +1106,7 @@ mod repr { #[test] fn packed() { - check_repr( + check( r#"#[repr(packed, $0)] struct Test;"#, expect![[r#" ba C @@ -1144,7 +1129,7 @@ mod repr { #[test] fn c() { - check_repr( + check( r#"#[repr(C, $0)] struct Test;"#, expect![[r#" ba align($0) @@ -1167,7 +1152,7 @@ mod repr { #[test] fn prim() { - check_repr( + check( r#"#[repr(usize, $0)] struct Test;"#, expect![[r#" ba C diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs index 30466148686..e117dbf4bdf 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs @@ -4,18 +4,17 @@ use expect_test::{expect, Expect}; use crate::{ config::AutoImportExclusionType, tests::{ - check_edit, check_empty, completion_list, completion_list_with_config, BASE_ITEMS_FIXTURE, + check, check_edit, check_with_base_items, completion_list_with_config, BASE_ITEMS_FIXTURE, TEST_CONFIG, }, CompletionConfig, }; -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}")); - expect.assert_eq(&actual) -} - -fn check_with_config(config: CompletionConfig<'_>, ra_fixture: &str, expect: Expect) { +fn check_with_config( + config: CompletionConfig<'_>, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, +) { let actual = completion_list_with_config( config, &format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"), @@ -28,7 +27,7 @@ fn check_with_config(config: CompletionConfig<'_>, ra_fixture: &str, expect: Exp #[test] fn complete_literal_struct_with_a_private_field() { // `FooDesc.bar` is private, the completion should not be triggered. - check( + check_with_base_items( r#" mod _69latrick { pub struct FooDesc { pub six: bool, pub neuf: Vec<String>, bar: bool } @@ -67,6 +66,7 @@ fn baz() { kw loop kw match kw mut + kw raw kw return kw self:: kw true @@ -79,7 +79,7 @@ fn baz() { #[test] fn completes_various_bindings() { - check_empty( + check( r#" fn func(param0 @ (param1, param2): (i32, i32)) { let letlocal = 92; @@ -125,7 +125,7 @@ fn func(param0 @ (param1, param2): (i32, i32)) { #[test] fn completes_all_the_things_in_fn_body() { - check( + check_with_base_items( r#" use non_existent::Unresolved; mod qualified { pub enum Enum { Variant } } @@ -191,7 +191,7 @@ impl Unit { ?? Unresolved "#]], ); - check( + check_with_base_items( r#" use non_existent::Unresolved; mod qualified { pub enum Enum { Variant } } @@ -224,7 +224,7 @@ impl Unit { #[test] fn complete_in_block() { - check_empty( + check( r#" fn foo() { if true { @@ -273,7 +273,7 @@ fn complete_in_block() { #[test] fn complete_after_if_expr() { - check_empty( + check( r#" fn foo() { if true {} @@ -321,7 +321,7 @@ fn complete_after_if_expr() { #[test] fn complete_in_match_arm() { - check_empty( + check( r#" fn foo() { match () { @@ -351,7 +351,7 @@ fn complete_in_match_arm() { #[test] fn completes_in_loop_ctx() { - check_empty( + check( r"fn my() { loop { $0 } }", expect![[r#" fn my() fn() @@ -390,7 +390,7 @@ fn completes_in_loop_ctx() { sn ppd "#]], ); - check_empty( + check( r"fn my() { loop { foo.$0 } }", expect![[r#" sn box Box::new(expr) @@ -415,7 +415,7 @@ fn completes_in_loop_ctx() { #[test] fn completes_in_let_initializer() { - check_empty( + check( r#"fn main() { let _ = $0 }"#, expect![[r#" fn main() fn() @@ -438,8 +438,116 @@ fn completes_in_let_initializer() { } #[test] +fn completes_after_ref_expr() { + check( + r#"fn main() { let _ = &$0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw mut + kw raw + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); + check( + r#"fn main() { let _ = &raw $0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw const + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw mut + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); + check( + r#"fn main() { let _ = &raw const $0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); + check( + r#"fn main() { let _ = &raw mut $0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ); + check( + r#"fn main() { let _ = &mut $0 }"#, + expect![[r#" + fn main() fn() + bt u32 u32 + kw crate:: + kw false + kw for + kw if + kw if let + kw loop + kw match + kw return + kw self:: + kw true + kw unsafe + kw while + kw while let + "#]], + ) +} + +#[test] fn struct_initializer_field_expr() { - check_empty( + check( r#" struct Foo { pub f: i32, @@ -475,7 +583,7 @@ fn foo() { fn shadowing_shows_single_completion() { cov_mark::check!(shadowing_shows_single_completion); - check_empty( + check( r#" fn foo() { let bar = 92; @@ -508,7 +616,7 @@ fn foo() { #[test] fn in_macro_expr_frag() { - check_empty( + check( r#" macro_rules! m { ($e:expr) => { $e } } fn quux(x: i32) { @@ -535,7 +643,7 @@ fn quux(x: i32) { kw while let "#]], ); - check_empty( + check( r" macro_rules! m { ($e:expr) => { $e } } fn quux(x: i32) { @@ -562,7 +670,7 @@ fn quux(x: i32) { kw while let "#]], ); - check_empty( + check( r#" macro_rules! m { ($e:expr) => { $e } } fn quux(x: i32) { @@ -595,7 +703,7 @@ fn quux(x: i32) { #[test] fn enum_qualified() { - check( + check_with_base_items( r#" impl Enum { type AssocType = (); @@ -619,7 +727,7 @@ fn func() { #[test] fn ty_qualified_no_drop() { - check_empty( + check( r#" //- minicore: drop struct Foo; @@ -636,7 +744,7 @@ fn func() { #[test] fn with_parens() { - check_empty( + check( r#" enum Enum { Variant() @@ -657,7 +765,7 @@ fn func() { #[test] fn detail_impl_trait_in_return_position() { - check_empty( + check( r" //- minicore: sized trait Trait<T> {} @@ -676,7 +784,7 @@ fn main() { #[test] fn detail_async_fn() { - check_empty( + check( r#" //- minicore: future, sized trait Trait<T> {} @@ -697,7 +805,7 @@ fn main() { #[test] fn detail_impl_trait_in_argument_position() { - check_empty( + check( r" //- minicore: sized trait Trait<T> {} @@ -717,7 +825,7 @@ fn main() { #[test] fn complete_record_expr_path() { - check( + check_with_base_items( r#" struct Zulu; impl Zulu { @@ -738,7 +846,7 @@ fn main() { #[test] fn variant_with_struct() { - check_empty( + check( r#" pub struct YoloVariant { pub f: usize @@ -813,7 +921,7 @@ fn return_value_no_block() { #[test] fn else_completion_after_if() { - check_empty( + check( r#" fn foo() { if foo {} $0 } "#, @@ -854,7 +962,7 @@ fn foo() { if foo {} $0 } sn ppd "#]], ); - check_empty( + check( r#" fn foo() { if foo {} el$0 } "#, @@ -895,7 +1003,7 @@ fn foo() { if foo {} el$0 } sn ppd "#]], ); - check_empty( + check( r#" fn foo() { bar(if foo {} $0) } "#, @@ -919,7 +1027,7 @@ fn foo() { bar(if foo {} $0) } kw while let "#]], ); - check_empty( + check( r#" fn foo() { bar(if foo {} el$0) } "#, @@ -943,7 +1051,7 @@ fn foo() { bar(if foo {} el$0) } kw while let "#]], ); - check_empty( + check( r#" fn foo() { if foo {} $0 let x = 92; } "#, @@ -984,7 +1092,7 @@ fn foo() { if foo {} $0 let x = 92; } sn ppd "#]], ); - check_empty( + check( r#" fn foo() { if foo {} el$0 let x = 92; } "#, @@ -1025,7 +1133,7 @@ fn foo() { if foo {} el$0 let x = 92; } sn ppd "#]], ); - check_empty( + check( r#" fn foo() { if foo {} el$0 { let x = 92; } } "#, @@ -1070,7 +1178,7 @@ fn foo() { if foo {} el$0 { let x = 92; } } #[test] fn expr_no_unstable_item_on_stable() { - check_empty( + check( r#" //- /main.rs crate:main deps:std use std::*; @@ -1121,7 +1229,7 @@ pub struct UnstableThisShouldNotBeListed; #[test] fn expr_unstable_item_on_nightly() { - check_empty( + check( r#" //- toolchain:nightly //- /main.rs crate:main deps:std @@ -1174,7 +1282,7 @@ pub struct UnstableButWeAreOnNightlyAnyway; #[test] fn inside_format_args_completions_work() { - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1200,7 +1308,7 @@ fn main() { sn unsafe unsafe {} "#]], ); - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1230,7 +1338,7 @@ fn main() { #[test] fn inside_faulty_format_args_completions_work() { - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1256,7 +1364,7 @@ fn main() { sn unsafe unsafe {} "#]], ); - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1282,7 +1390,7 @@ fn main() { sn unsafe unsafe {} "#]], ); - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1308,7 +1416,7 @@ fn main() { sn unsafe unsafe {} "#]], ); - check_empty( + check( r#" //- minicore: fmt struct Foo; @@ -1340,7 +1448,7 @@ fn main() { #[test] fn macro_that_ignores_completion_marker() { - check( + check_with_base_items( r#" macro_rules! helper { ($v:ident) => {}; @@ -1788,7 +1896,7 @@ fn foo<T: ExcludedTrait>() { #[test] fn hide_ragennew_synthetic_identifiers() { - check_empty( + check( r#" //- minicore: iterator fn bar() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs index d413977f7c8..d491e438fef 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs @@ -6,11 +6,15 @@ use crate::{ CompletionConfig, }; -fn check(ra_fixture: &str, expect: Expect) { +fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { check_with_config(TEST_CONFIG, ra_fixture, expect); } -fn check_with_config(config: CompletionConfig<'_>, ra_fixture: &str, expect: Expect) { +fn check_with_config( + config: CompletionConfig<'_>, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, +) { let (db, position) = crate::tests::position(ra_fixture); let (ctx, analysis) = crate::context::CompletionContext::new(&db, position, &config).unwrap(); @@ -1742,7 +1746,7 @@ fn intrinsics() { fn function() { transmute$0 } - "#, +"#, expect![[r#" fn transmute(…) (use core::mem::transmute) unsafe fn(Src) -> Dst "#]], @@ -1763,7 +1767,9 @@ fn function() { mem::transmute$0 } "#, - expect![""], + expect![[r#" + fn transmute(…) (use core::mem) unsafe fn(Src) -> Dst + "#]], ); } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs index 4a89f874e15..451ce07c745 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/fn_param.rs @@ -1,16 +1,6 @@ -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{completion_list, completion_list_with_trigger_character}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} - -fn check_with_trigger_character(ra_fixture: &str, trigger_character: char, expect: Expect) { - let actual = completion_list_with_trigger_character(ra_fixture, Some(trigger_character)); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_with_trigger_character}; #[test] fn only_param() { @@ -124,7 +114,7 @@ fn trigger_by_l_paren() { r#" fn foo($0) "#, - '(', + Some('('), expect![[]], ) } diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs index 79561a0419f..bea6d60769c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs @@ -2,20 +2,13 @@ //! //! Except for use items which are tested in [super::use_tree] and mod declarations with are tested //! in [crate::completions::mod_]. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{completion_list, BASE_ITEMS_FIXTURE}; - -use super::check_edit; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check_edit, check_with_base_items}; #[test] fn target_type_or_trait_in_impl_block() { - check( + check_with_base_items( r#" impl Tra$0 "#, @@ -37,7 +30,7 @@ impl Tra$0 #[test] fn target_type_in_trait_impl_block() { - check( + check_with_base_items( r#" impl Trait for Str$0 "#, @@ -59,7 +52,7 @@ impl Trait for Str$0 #[test] fn after_trait_name_in_trait_def() { - check( + check_with_base_items( r"trait A $0", expect![[r#" kw where @@ -69,21 +62,21 @@ fn after_trait_name_in_trait_def() { #[test] fn after_target_name_in_impl() { - check( + check_with_base_items( r"impl Trait $0", expect![[r#" kw for kw where "#]], ); - check( + check_with_base_items( r"impl Trait f$0", expect![[r#" kw for kw where "#]], ); - check( + check_with_base_items( r"impl Trait for Type $0", expect![[r#" kw where @@ -93,44 +86,44 @@ fn after_target_name_in_impl() { #[test] fn completes_where() { - check( + check_with_base_items( r"struct Struct $0", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"struct Struct $0 {}", expect![[r#" kw where "#]], ); // FIXME: This shouldn't be completed here - check( + check_with_base_items( r"struct Struct $0 ()", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"fn func() $0", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"enum Enum $0", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"enum Enum $0 {}", expect![[r#" kw where "#]], ); - check( + check_with_base_items( r"trait Trait $0 {}", expect![[r#" kw where @@ -140,7 +133,7 @@ fn completes_where() { #[test] fn before_record_field() { - check( + check_with_base_items( r#" struct Foo { $0 @@ -244,7 +237,7 @@ impl Copy for S where $0 #[test] fn test_is_not_considered_macro() { - check( + check_with_base_items( r#" #[rustc_builtin] pub macro test($item:item) { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs index d3d52dc6dfc..841c42123a0 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs @@ -1,16 +1,11 @@ //! Completion tests for item list position. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_edit, check_with_base_items}; #[test] fn in_mod_item_list() { - check( + check_with_base_items( r#"mod tests { $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -43,7 +38,7 @@ fn in_mod_item_list() { #[test] fn in_source_file_item_list() { - check( + check_with_base_items( r#"$0"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -76,7 +71,7 @@ fn in_source_file_item_list() { #[test] fn in_item_list_after_attr() { - check( + check_with_base_items( r#"#[attr] $0"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -109,7 +104,7 @@ fn in_item_list_after_attr() { #[test] fn in_qualified_path() { - check( + check_with_base_items( r#"crate::$0"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -120,7 +115,7 @@ fn in_qualified_path() { #[test] fn after_unsafe_token() { - check( + check_with_base_items( r#"unsafe $0"#, expect![[r#" kw async @@ -134,7 +129,7 @@ fn after_unsafe_token() { #[test] fn after_async_token() { - check( + check_with_base_items( r#"async $0"#, expect![[r#" kw fn @@ -145,7 +140,7 @@ fn after_async_token() { #[test] fn after_visibility() { - check( + check_with_base_items( r#"pub $0"#, expect![[r#" kw async @@ -167,7 +162,7 @@ fn after_visibility() { #[test] fn after_visibility_unsafe() { - check( + check_with_base_items( r#"pub unsafe $0"#, expect![[r#" kw async @@ -179,7 +174,7 @@ fn after_visibility_unsafe() { #[test] fn in_impl_assoc_item_list() { - check( + check_with_base_items( r#"impl Struct { $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -199,7 +194,7 @@ fn in_impl_assoc_item_list() { #[test] fn in_impl_assoc_item_list_after_attr() { - check( + check_with_base_items( r#"impl Struct { #[attr] $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -219,7 +214,7 @@ fn in_impl_assoc_item_list_after_attr() { #[test] fn in_trait_assoc_item_list() { - check( + check_with_base_items( r"trait Foo { $0 }", expect![[r#" ma makro!(…) macro_rules! makro @@ -237,7 +232,7 @@ fn in_trait_assoc_item_list() { #[test] fn in_trait_assoc_fn_missing_body() { - check( + check_with_base_items( r#"trait Foo { fn function(); $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -255,7 +250,7 @@ fn in_trait_assoc_fn_missing_body() { #[test] fn in_trait_assoc_const_missing_body() { - check( + check_with_base_items( r#"trait Foo { const CONST: (); $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -273,7 +268,7 @@ fn in_trait_assoc_const_missing_body() { #[test] fn in_trait_assoc_type_aliases_missing_ty() { - check( + check_with_base_items( r#"trait Foo { type Type; $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -291,7 +286,7 @@ fn in_trait_assoc_type_aliases_missing_ty() { #[test] fn in_trait_impl_assoc_item_list() { - check( + check_with_base_items( r#" trait Test { type Type0; @@ -326,7 +321,7 @@ impl Test for () { #[test] fn in_trait_impl_no_unstable_item_on_stable() { - check_empty( + check( r#" trait Test { #[unstable] @@ -350,7 +345,7 @@ impl Test for () { #[test] fn in_trait_impl_unstable_item_on_nightly() { - check_empty( + check( r#" //- toolchain:nightly trait Test { @@ -378,7 +373,7 @@ impl Test for () { #[test] fn after_unit_struct() { - check( + check_with_base_items( r#"struct S; f$0"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -500,7 +495,7 @@ type O = $0; #[test] fn inside_extern_blocks() { // Should suggest `fn`, `static`, `unsafe` - check( + check_with_base_items( r#"extern { $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -517,7 +512,7 @@ fn inside_extern_blocks() { ); // Should suggest `fn`, `static`, `safe`, `unsafe` - check( + check_with_base_items( r#"unsafe extern { $0 }"#, expect![[r#" ma makro!(…) macro_rules! makro @@ -534,7 +529,7 @@ fn inside_extern_blocks() { "#]], ); - check( + check_with_base_items( r#"unsafe extern { pub safe $0 }"#, expect![[r#" kw fn @@ -542,7 +537,7 @@ fn inside_extern_blocks() { "#]], ); - check( + check_with_base_items( r#"unsafe extern { pub unsafe $0 }"#, expect![[r#" kw fn diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs index 2f1f555e524..9ec27252fd7 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/pattern.rs @@ -1,16 +1,11 @@ //! Completion tests for pattern position. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_edit, check_empty, completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_edit, check_with_base_items}; #[test] fn wildcard() { - check( + check_with_base_items( r#" fn quux() { let _$0 @@ -22,7 +17,7 @@ fn quux() { #[test] fn ident_rebind_pat() { - check_empty( + check( r#" fn quux() { let en$0 @ x @@ -37,7 +32,7 @@ fn quux() { #[test] fn ident_ref_pat() { - check_empty( + check( r#" fn quux() { let ref en$0 @@ -47,7 +42,7 @@ fn quux() { kw mut "#]], ); - check_empty( + check( r#" fn quux() { let ref en$0 @ x @@ -61,7 +56,7 @@ fn quux() { #[test] fn ident_ref_mut_pat() { - check_empty( + check( r#" fn quux() { let ref mut en$0 @@ -69,7 +64,7 @@ fn quux() { "#, expect![[r#""#]], ); - check_empty( + check( r#" fn quux() { let ref mut en$0 @ x @@ -81,7 +76,7 @@ fn quux() { #[test] fn ref_pat() { - check_empty( + check( r#" fn quux() { let &en$0 @@ -91,7 +86,7 @@ fn quux() { kw mut "#]], ); - check_empty( + check( r#" fn quux() { let &mut en$0 @@ -99,7 +94,7 @@ fn quux() { "#, expect![[r#""#]], ); - check_empty( + check( r#" fn foo() { for &$0 in () {} @@ -113,7 +108,7 @@ fn foo() { #[test] fn refutable() { - check( + check_with_base_items( r#" fn foo() { if let a$0 @@ -139,7 +134,7 @@ fn foo() { #[test] fn irrefutable() { - check( + check_with_base_items( r#" enum SingleVariantEnum { Variant @@ -168,7 +163,7 @@ fn foo() { #[test] fn in_param() { - check( + check_with_base_items( r#" fn foo(a$0) { } @@ -185,7 +180,7 @@ fn foo(a$0) { kw ref "#]], ); - check( + check_with_base_items( r#" fn foo(a$0: Tuple) { } @@ -207,7 +202,7 @@ fn foo(a$0: Tuple) { #[test] fn only_fn_like_macros() { - check_empty( + check( r#" macro_rules! m { ($e:expr) => { $e } } @@ -228,7 +223,7 @@ fn foo() { #[test] fn in_simple_macro_call() { - check_empty( + check( r#" macro_rules! m { ($e:expr) => { $e } } enum E { X } @@ -249,7 +244,7 @@ fn foo() { #[test] fn omits_private_fields_pat() { - check_empty( + check( r#" mod foo { pub struct Record { pub field: i32, _field: i32 } @@ -277,7 +272,7 @@ fn outer() { #[test] fn completes_self_pats() { - check_empty( + check( r#" struct Foo(i32); impl Foo { @@ -301,7 +296,7 @@ impl Foo { #[test] fn enum_qualified() { - check( + check_with_base_items( r#" impl Enum { type AssocType = (); @@ -323,7 +318,7 @@ fn func() { #[test] fn completes_in_record_field_pat() { - check_empty( + check( r#" struct Foo { bar: Bar } struct Bar(u32); @@ -342,7 +337,7 @@ fn outer(Foo { bar: $0 }: Foo) {} #[test] fn skips_in_record_field_pat_name() { - check_empty( + check( r#" struct Foo { bar: Bar } struct Bar(u32); @@ -357,7 +352,7 @@ fn outer(Foo { bar$0 }: Foo) {} #[test] fn completes_in_record_field_pat_with_generic_type_alias() { - check_empty( + check( r#" type Wrap<T> = T; @@ -386,7 +381,7 @@ fn main() { #[test] fn completes_in_fn_param() { - check_empty( + check( r#" struct Foo { bar: Bar } struct Bar(u32); @@ -405,7 +400,7 @@ fn foo($0) {} #[test] fn completes_in_closure_param() { - check_empty( + check( r#" struct Foo { bar: Bar } struct Bar(u32); @@ -426,7 +421,7 @@ fn foo() { #[test] fn completes_no_delims_if_existing() { - check_empty( + check( r#" struct Bar(u32); fn foo() { @@ -441,7 +436,7 @@ fn foo() { kw self:: "#]], ); - check_empty( + check( r#" struct Foo { bar: u32 } fn foo() { @@ -456,7 +451,7 @@ fn foo() { kw self:: "#]], ); - check_empty( + check( r#" enum Enum { TupleVariant(u32) @@ -471,7 +466,7 @@ fn foo() { bn TupleVariant TupleVariant "#]], ); - check_empty( + check( r#" enum Enum { RecordVariant { field: u32 } @@ -519,7 +514,7 @@ fn foo() { #[test] fn completes_enum_variant_pat_escape() { cov_mark::check!(enum_variant_pattern_path); - check_empty( + check( r#" enum Enum { A, @@ -544,7 +539,7 @@ fn foo() { "#]], ); - check_empty( + check( r#" enum Enum { A, @@ -569,7 +564,7 @@ fn foo() { #[test] fn completes_associated_const() { - check_empty( + check( r#" #[derive(PartialEq, Eq)] struct Ty(u8); @@ -590,7 +585,7 @@ fn f(t: Ty) { "#]], ); - check_empty( + check( r#" enum MyEnum {} @@ -612,7 +607,7 @@ fn f(e: MyEnum) { "#]], ); - check_empty( + check( r#" union U { i: i32, @@ -637,7 +632,7 @@ fn f(u: U) { "#]], ); - check_empty( + check( r#" #![rustc_coherence_is_core] #[lang = "u32"] @@ -659,7 +654,7 @@ fn f(v: u32) { #[test] fn in_method_param() { - check_empty( + check( r#" struct Ty(u8); @@ -680,7 +675,7 @@ impl Ty { kw ref "#]], ); - check_empty( + check( r#" struct Ty(u8); @@ -701,7 +696,7 @@ impl Ty { kw ref "#]], ); - check_empty( + check( r#" struct Ty(u8); @@ -722,7 +717,7 @@ impl Ty { kw ref "#]], ); - check_empty( + check( r#" struct Ty(u8); @@ -743,7 +738,7 @@ impl Ty { #[test] fn through_alias() { - check_empty( + check( r#" enum Enum<T> { Unit, @@ -770,7 +765,7 @@ fn f(x: EnumAlias<u8>) { #[test] fn pat_no_unstable_item_on_stable() { - check_empty( + check( r#" //- /main.rs crate:main deps:std use std::*; @@ -795,7 +790,7 @@ pub enum Enum { #[test] fn pat_unstable_item_on_nightly() { - check_empty( + check( r#" //- toolchain:nightly //- /main.rs crate:main deps:std @@ -908,7 +903,7 @@ fn foo() { ); // Do not suggest reserved keywords - check_empty( + check( r#" struct Struct; @@ -926,7 +921,7 @@ fn foo() { #[test] fn private_item_in_module_in_function_body() { - check_empty( + check( r#" fn main() { mod foo { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs index c1926359efc..65036f6a224 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs @@ -1,17 +1,12 @@ //! Completion tests for predicates and bounds. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_empty, completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_with_base_items}; #[test] fn predicate_start() { // FIXME: `for` kw - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where $0 {} "#, @@ -34,7 +29,7 @@ struct Foo<'lt, T, const C: usize> where $0 {} #[test] fn bound_for_type_pred() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where T: $0 {} "#, @@ -52,7 +47,7 @@ struct Foo<'lt, T, const C: usize> where T: $0 {} fn bound_for_lifetime_pred() { // FIXME: should only show lifetimes here, that is we shouldn't get any completions here when not typing // a `'` - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where 'lt: $0 {} "#, @@ -68,7 +63,7 @@ struct Foo<'lt, T, const C: usize> where 'lt: $0 {} #[test] fn bound_for_for_pred() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {} "#, @@ -84,7 +79,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> T: $0 {} #[test] fn param_list_for_for_pred() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> where for<'a> $0 {} "#, @@ -107,7 +102,7 @@ struct Foo<'lt, T, const C: usize> where for<'a> $0 {} #[test] fn pred_on_fn_in_impl() { - check( + check_with_base_items( r#" impl Record { fn method(self) where $0 {} @@ -132,7 +127,7 @@ impl Record { #[test] fn pred_no_unstable_item_on_stable() { - check_empty( + check( r#" //- /main.rs crate:main deps:std use std::*; @@ -151,7 +146,7 @@ pub trait Trait {} #[test] fn pred_unstable_item_on_nightly() { - check_empty( + check( r#" //- toolchain:nightly //- /main.rs crate:main deps:std diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs index afc286b6fb4..6b1dfe366ce 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs @@ -1,12 +1,7 @@ //! Completion tests for expressions. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::completion_list; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} +use crate::tests::check; #[test] fn complete_dot_in_attr() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs index d81b3d697aa..9ab66243b5c 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/raw_identifiers.rs @@ -4,7 +4,7 @@ use itertools::Itertools; use crate::tests::{completion_list_with_config_raw, position, TEST_CONFIG}; -fn check(ra_fixture: &str, expect: Expect) { +fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let completions = completion_list_with_config_raw(TEST_CONFIG, ra_fixture, true, None); let (db, position) = position(ra_fixture); let mut actual = db.file_text(position.file_id).to_string(); diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs index a9c9f604e07..a1013b86548 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs @@ -1,14 +1,9 @@ -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::completion_list; +use crate::tests::check; use super::check_edit; -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual); -} - #[test] fn without_default_impl() { check( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs index 6cfb2231a99..2b05184bdbe 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs @@ -5,32 +5,12 @@ use ide_db::SymbolKind; use crate::{ tests::{ - check_edit, completion_list, completion_list_no_kw, completion_list_with_trigger_character, + check, check_edit, check_no_kw, check_with_trigger_character, do_completion_with_config, + TEST_CONFIG, }, CompletionItemKind, }; -use super::{do_completion_with_config, TEST_CONFIG}; - -fn check_no_kw(ra_fixture: &str, expect: Expect) { - let actual = completion_list_no_kw(ra_fixture); - expect.assert_eq(&actual) -} - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} - -pub(crate) fn check_with_trigger_character( - ra_fixture: &str, - trigger_character: Option<char>, - expect: Expect, -) { - let actual = completion_list_with_trigger_character(ra_fixture, trigger_character); - expect.assert_eq(&actual) -} - #[test] fn completes_if_prefix_is_keyword() { check_edit( diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs index 9ea262bcc59..c7e2d058257 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs @@ -1,16 +1,11 @@ //! Completion tests for type position. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{check_empty, completion_list, BASE_ITEMS_FIXTURE}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}\n{ra_fixture}")); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_with_base_items}; #[test] fn record_field_ty() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize> { f: $0 @@ -37,7 +32,7 @@ struct Foo<'lt, T, const C: usize> { #[test] fn tuple_struct_field() { - check( + check_with_base_items( r#" struct Foo<'lt, T, const C: usize>(f$0); "#, @@ -65,7 +60,7 @@ struct Foo<'lt, T, const C: usize>(f$0); #[test] fn fn_return_type() { - check( + check_with_base_items( r#" fn x<'lt, T, const C: usize>() -> $0 "#, @@ -88,7 +83,7 @@ fn x<'lt, T, const C: usize>() -> $0 #[test] fn fn_return_type_no_local_items() { - check( + check_with_base_items( r#" fn foo() -> B$0 { struct Bar; @@ -118,7 +113,7 @@ fn foo() -> B$0 { #[test] fn inferred_type_const() { - check( + check_with_base_items( r#" struct Foo<T>(T); const FOO: $0 = Foo(2); @@ -143,7 +138,7 @@ const FOO: $0 = Foo(2); #[test] fn inferred_type_closure_param() { - check( + check_with_base_items( r#" fn f1(f: fn(i32) -> i32) {} fn f2() { @@ -169,7 +164,7 @@ fn f2() { #[test] fn inferred_type_closure_return() { - check( + check_with_base_items( r#" fn f1(f: fn(u64) -> u64) {} fn f2() { @@ -197,7 +192,7 @@ fn f2() { #[test] fn inferred_type_fn_return() { - check( + check_with_base_items( r#" fn f2(x: u64) -> $0 { x + 5 @@ -222,7 +217,7 @@ fn f2(x: u64) -> $0 { #[test] fn inferred_type_fn_param() { - check( + check_with_base_items( r#" fn f1(x: i32) {} fn f2(x: $0) { @@ -248,7 +243,7 @@ fn f2(x: $0) { #[test] fn inferred_type_not_in_the_scope() { - check( + check_with_base_items( r#" mod a { pub struct Foo<T>(T); @@ -282,7 +277,7 @@ fn foo<'lt, T, const C: usize>() { #[test] fn inferred_type_let() { - check( + check_with_base_items( r#" struct Foo<T>(T); fn foo<'lt, T, const C: usize>() { @@ -311,7 +306,7 @@ fn foo<'lt, T, const C: usize>() { #[test] fn body_type_pos() { - check( + check_with_base_items( r#" fn foo<'lt, T, const C: usize>() { let local = (); @@ -333,7 +328,7 @@ fn foo<'lt, T, const C: usize>() { kw self:: "#]], ); - check( + check_with_base_items( r#" fn foo<'lt, T, const C: usize>() { let local = (); @@ -356,7 +351,7 @@ fn foo<'lt, T, const C: usize>() { #[test] fn completes_types_and_const_in_arg_list() { cov_mark::check!(complete_assoc_type_in_generics_list); - check( + check_with_base_items( r#" trait Trait1 { type Super; @@ -372,7 +367,7 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} ta Super = (as Trait1) type Super "#]], ); - check( + check_with_base_items( r#" trait Trait1 { type Super; @@ -400,7 +395,7 @@ fn foo<'lt, T: Trait2<$0>, const CONST_PARAM: usize>(_: T) {} kw self:: "#]], ); - check( + check_with_base_items( r#" trait Trait2<T> { type Foo; @@ -424,7 +419,7 @@ fn foo<'lt, T: Trait2<self::$0>, const CONST_PARAM: usize>(_: T) {} #[test] fn no_assoc_completion_outside_type_bounds() { - check( + check_with_base_items( r#" struct S; trait Tr<T> { @@ -454,7 +449,7 @@ impl Tr<$0 #[test] fn enum_qualified() { - check( + check_with_base_items( r#" impl Enum { type AssocType = (); @@ -471,7 +466,7 @@ fn func(_: Enum::$0) {} #[test] fn completes_type_parameter_or_associated_type() { - check( + check_with_base_items( r#" trait MyTrait<T, U> { type Item1; @@ -496,7 +491,7 @@ fn f(t: impl MyTrait<u$0 "#]], ); - check( + check_with_base_items( r#" trait MyTrait<T, U> { type Item1; @@ -521,7 +516,7 @@ fn f(t: impl MyTrait<u8, u$0 "#]], ); - check( + check_with_base_items( r#" trait MyTrait<T, U> { type Item1; @@ -539,7 +534,7 @@ fn f(t: impl MyTrait<u8, u8, I$0 #[test] fn completes_type_parameter_or_associated_type_with_default_value() { - check( + check_with_base_items( r#" trait MyTrait<T, U = u8> { type Item1; @@ -564,7 +559,7 @@ fn f(t: impl MyTrait<u$0 "#]], ); - check( + check_with_base_items( r#" trait MyTrait<T, U = u8> { type Item1; @@ -591,7 +586,7 @@ fn f(t: impl MyTrait<u8, u$0 "#]], ); - check( + check_with_base_items( r#" trait MyTrait<T, U = u8> { type Item1; @@ -609,7 +604,7 @@ fn f(t: impl MyTrait<u8, u8, I$0 #[test] fn completes_types_after_associated_type() { - check( + check_with_base_items( r#" trait MyTrait { type Item1; @@ -634,7 +629,7 @@ fn f(t: impl MyTrait<Item1 = $0 "#]], ); - check( + check_with_base_items( r#" trait MyTrait { type Item1; @@ -659,7 +654,7 @@ fn f(t: impl MyTrait<Item1 = u8, Item2 = $0 "#]], ); - check( + check_with_base_items( r#" trait MyTrait { const C: usize; @@ -678,7 +673,7 @@ fn f(t: impl MyTrait<C = $0 #[test] fn type_pos_no_unstable_type_on_stable() { - check_empty( + check( r#" //- /main.rs crate:main deps:std use std::*; @@ -702,7 +697,7 @@ pub struct S; #[test] fn type_pos_unstable_type_on_nightly() { - check_empty( + check( r#" //- toolchain:nightly //- /main.rs crate:main deps:std @@ -729,7 +724,7 @@ pub struct S; #[test] fn completes_const_and_type_generics_separately() { // Function generic params - check( + check_with_base_items( r#" struct Foo; const X: usize = 0; @@ -756,7 +751,7 @@ fn completes_const_and_type_generics_separately() { // FIXME: This should probably also suggest completions for types, at least those that have // associated constants usable in this position. For example, a user could be typing // `foo::<_, { usize::MAX }>()`, but we currently don't suggest `usize` in constant position. - check( + check_with_base_items( r#" struct Foo; const X: usize = 0; @@ -775,7 +770,7 @@ fn completes_const_and_type_generics_separately() { ); // Method generic params - check( + check_with_base_items( r#" const X: usize = 0; struct Foo; @@ -799,7 +794,7 @@ fn completes_const_and_type_generics_separately() { kw self:: "#]], ); - check( + check_with_base_items( r#" const X: usize = 0; struct Foo; @@ -818,7 +813,7 @@ fn completes_const_and_type_generics_separately() { ); // Associated type generic params - check( + check_with_base_items( r#" const X: usize = 0; struct Foo; @@ -843,7 +838,7 @@ fn completes_const_and_type_generics_separately() { kw self:: "#]], ); - check( + check_with_base_items( r#" const X: usize = 0; struct Foo; @@ -862,7 +857,7 @@ fn completes_const_and_type_generics_separately() { ); // Type generic params - check( + check_with_base_items( r#" const X: usize = 0; struct Foo<T, const N: usize>(T); @@ -880,7 +875,7 @@ fn completes_const_and_type_generics_separately() { ); // Type alias generic params - check( + check_with_base_items( r#" const X: usize = 0; struct Foo<T, const N: usize>(T); @@ -899,7 +894,7 @@ fn completes_const_and_type_generics_separately() { ); // Enum variant params - check( + check_with_base_items( r#" const X: usize = 0; enum Foo<T, const N: usize> { A(T), B } @@ -917,7 +912,7 @@ fn completes_const_and_type_generics_separately() { ); // Trait params - check( + check_with_base_items( r#" const X: usize = 0; trait Foo<T, const N: usize> {} @@ -933,7 +928,7 @@ fn completes_const_and_type_generics_separately() { ); // Trait alias params - check( + check_with_base_items( r#" #![feature(trait_alias)] const X: usize = 0; @@ -951,7 +946,7 @@ fn completes_const_and_type_generics_separately() { ); // Omitted lifetime params - check( + check_with_base_items( r#" struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>); fn foo<'a>() { S::<F$0, _>; } @@ -964,7 +959,7 @@ fn foo<'a>() { S::<F$0, _>; } "#]], ); // Explicit lifetime params - check( + check_with_base_items( r#" struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>); fn foo<'a>() { S::<'static, 'static, F$0, _>; } @@ -976,7 +971,7 @@ fn foo<'a>() { S::<'static, 'static, F$0, _>; } kw self:: "#]], ); - check( + check_with_base_items( r#" struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>); fn foo<'a>() { S::<'static, F$0, _, _>; } @@ -992,7 +987,7 @@ fn foo<'a>() { S::<'static, F$0, _, _>; } #[test] fn complete_traits_on_impl_trait_block() { - check( + check_with_base_items( r#" trait Foo {} @@ -1012,7 +1007,7 @@ impl $0 for Bar { } #[test] fn complete_traits_with_path_on_impl_trait_block() { - check( + check_with_base_items( r#" mod outer { pub trait Foo {} diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs index 2ea2e4e4c96..04b3a47a64d 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs @@ -1,12 +1,7 @@ //! Completion tests for use trees. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::completion_list; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} +use crate::tests::check; #[test] fn use_tree_completion() { diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs index c18d6e66dd6..4b5a0ac1c2b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/visibility.rs @@ -1,17 +1,7 @@ //! Completion tests for visibility modifiers. -use expect_test::{expect, Expect}; +use expect_test::expect; -use crate::tests::{completion_list, completion_list_with_trigger_character}; - -fn check(ra_fixture: &str, expect: Expect) { - let actual = completion_list(ra_fixture); - expect.assert_eq(&actual) -} - -fn check_with_trigger_character(ra_fixture: &str, trigger_character: char, expect: Expect) { - let actual = completion_list_with_trigger_character(ra_fixture, Some(trigger_character)); - expect.assert_eq(&actual) -} +use crate::tests::{check, check_with_trigger_character}; #[test] fn empty_pub() { @@ -20,7 +10,7 @@ fn empty_pub() { r#" pub($0) "#, - '(', + Some('('), expect![[r#" kw crate kw in diff --git a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs index 7482491fc63..11808fed3be 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/active_parameter.rs @@ -4,7 +4,7 @@ use either::Either; use hir::{InFile, Semantics, Type}; use parser::T; use syntax::{ - ast::{self, HasArgList, HasName}, + ast::{self, AstChildren, HasArgList, HasAttrs, HasName}, match_ast, AstNode, NodeOrToken, SyntaxToken, }; @@ -37,6 +37,10 @@ impl ActiveParameter { _ => None, }) } + + pub fn attrs(&self) -> Option<AstChildren<ast::Attr>> { + self.src.as_ref().and_then(|param| Some(param.value.as_ref().right()?.attrs())) + } } /// Returns a [`hir::Callable`] this token is a part of and its argument index of said callable. diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs index 2d30bb41273..49d26dfe25c 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs @@ -32,6 +32,7 @@ pub enum Definition { Field(Field), TupleField(TupleField), Module(Module), + Crate(Crate), Function(Function), Adt(Adt), Variant(Variant), @@ -62,14 +63,19 @@ impl Definition { pub fn krate(&self, db: &RootDatabase) -> Option<Crate> { Some(match self { Definition::Module(m) => m.krate(), + &Definition::Crate(it) => it, _ => self.module(db)?.krate(), }) } + /// Returns the module this definition resides in. + /// + /// As such, for modules themselves this will return the parent module. pub fn module(&self, db: &RootDatabase) -> Option<Module> { let module = match self { Definition::Macro(it) => it.module(db), Definition::Module(it) => it.parent(db)?, + Definition::Crate(_) => return None, Definition::Field(it) => it.parent_def(db).module(db), Definition::Function(it) => it.module(db), Definition::Adt(it) => it.module(db), @@ -86,11 +92,11 @@ impl Definition { Definition::ExternCrateDecl(it) => it.module(db), Definition::DeriveHelper(it) => it.derive().module(db), Definition::InlineAsmOperand(it) => it.parent(db).module(db), + Definition::ToolModule(t) => t.krate().root_module(), Definition::BuiltinAttr(_) | Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) | Definition::TupleField(_) - | Definition::ToolModule(_) | Definition::InlineAsmRegOrRegClass(_) => return None, }; Some(module) @@ -108,6 +114,7 @@ impl Definition { match self { Definition::Macro(it) => Some(it.module(db).into()), Definition::Module(it) => it.parent(db).map(Definition::Module), + Definition::Crate(_) => None, Definition::Field(it) => Some(it.parent_def(db).into()), Definition::Function(it) => container_to_definition(it.container(db)), Definition::Adt(it) => Some(it.module(db).into()), @@ -137,6 +144,7 @@ impl Definition { let vis = match self { Definition::Field(sf) => sf.visibility(db), Definition::Module(it) => it.visibility(db), + Definition::Crate(_) => return None, Definition::Function(it) => it.visibility(db), Definition::Adt(it) => it.visibility(db), Definition::Const(it) => it.visibility(db), @@ -146,8 +154,8 @@ impl Definition { Definition::TypeAlias(it) => it.visibility(db), Definition::Variant(it) => it.visibility(db), Definition::ExternCrateDecl(it) => it.visibility(db), + Definition::Macro(it) => it.visibility(db), Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public, - Definition::Macro(_) => return None, Definition::BuiltinAttr(_) | Definition::BuiltinLifetime(_) | Definition::ToolModule(_) @@ -167,6 +175,9 @@ impl Definition { Definition::Macro(it) => it.name(db), Definition::Field(it) => it.name(db), Definition::Module(it) => it.name(db)?, + Definition::Crate(it) => { + Name::new_symbol_root(it.display_name(db)?.crate_name().symbol().clone()) + } Definition::Function(it) => it.name(db), Definition::Adt(it) => it.name(db), Definition::Variant(it) => it.name(db), @@ -202,6 +213,7 @@ impl Definition { Definition::Macro(it) => it.docs(db), Definition::Field(it) => it.docs(db), Definition::Module(it) => it.docs(db), + Definition::Crate(it) => it.docs(db), Definition::Function(it) => it.docs(db), Definition::Adt(it) => it.docs(db), Definition::Variant(it) => it.docs(db), @@ -282,6 +294,7 @@ impl Definition { Definition::Field(it) => it.display(db, edition).to_string(), Definition::TupleField(it) => it.display(db, edition).to_string(), Definition::Module(it) => it.display(db, edition).to_string(), + Definition::Crate(it) => it.display(db, edition).to_string(), Definition::Function(it) => it.display(db, edition).to_string(), Definition::Adt(it) => it.display(db, edition).to_string(), Definition::Variant(it) => it.display(db, edition).to_string(), @@ -415,7 +428,7 @@ impl IdentClass { } IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => { res.push((Definition::ExternCrateDecl(decl), None)); - res.push((Definition::Module(krate.root_module()), None)); + res.push((Definition::Crate(krate), None)); } IdentClass::Operator( OperatorClass::Await(func) @@ -456,7 +469,7 @@ impl IdentClass { } IdentClass::NameRefClass(NameRefClass::ExternCrateShorthand { decl, krate }) => { res.push(Definition::ExternCrateDecl(decl)); - res.push(Definition::Module(krate.root_module())); + res.push(Definition::Crate(krate)); } IdentClass::Operator(_) => (), } @@ -800,7 +813,7 @@ impl NameRefClass { let extern_crate = sema.to_def(&extern_crate_ast)?; let krate = extern_crate.resolved_crate(sema.db)?; Some(if extern_crate_ast.rename().is_some() { - NameRefClass::Definition(Definition::Module(krate.root_module()), None) + NameRefClass::Definition(Definition::Crate(krate), None) } else { NameRefClass::ExternCrateShorthand { krate, decl: extern_crate } }) @@ -976,3 +989,19 @@ impl From<GenericDef> for Definition { } } } + +impl TryFrom<Definition> for GenericDef { + type Error = (); + fn try_from(def: Definition) -> Result<Self, Self::Error> { + match def { + Definition::Function(it) => Ok(it.into()), + Definition::Adt(it) => Ok(it.into()), + Definition::Trait(it) => Ok(it.into()), + Definition::TraitAlias(it) => Ok(it.into()), + Definition::TypeAlias(it) => Ok(it.into()), + Definition::SelfType(it) => Ok(it.into()), + Definition::Const(it) => Ok(it.into()), + _ => Err(()), + } + } +} diff --git a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs index a0ef0f90a65..b83efcd02f7 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/documentation.rs @@ -178,7 +178,7 @@ macro_rules! impl_has_docs { impl_has_docs![ Variant, Field, Static, Const, Trait, TraitAlias, TypeAlias, Macro, Function, Adt, Module, - Impl, + Impl, Crate, ]; macro_rules! impl_has_docs_enum { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs index ba6e50abf65..9e3506d6f53 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs @@ -106,6 +106,10 @@ impl FamousDefs<'_, '_> { self.find_trait("core:marker:Copy") } + pub fn core_marker_Sized(&self) -> Option<Trait> { + self.find_trait("core:marker:Sized") + } + pub fn core_future_Future(&self) -> Option<Trait> { self.find_trait("core:future:Future") } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs index 8f0be1d9035..ad86d855b55 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs @@ -1,15 +1,17 @@ //! Look up accessible paths for items. +use std::ops::ControlFlow; + use hir::{ db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, Crate, HasCrate, ImportPathConfig, - ItemInNs, ModPath, Module, ModuleDef, PathResolution, PrefixKind, ScopeDef, Semantics, + ItemInNs, ModPath, Module, ModuleDef, Name, PathResolution, PrefixKind, ScopeDef, Semantics, SemanticsScope, Trait, TyFingerprint, Type, }; use itertools::Itertools; use rustc_hash::{FxHashMap, FxHashSet}; use syntax::{ ast::{self, make, HasName}, - AstNode, SmolStr, SyntaxNode, + AstNode, SyntaxNode, }; use crate::{ @@ -51,7 +53,7 @@ pub struct TraitImportCandidate { #[derive(Debug)] pub struct PathImportCandidate { /// Optional qualifier before name. - pub qualifier: Vec<SmolStr>, + pub qualifier: Vec<Name>, /// The name the item (struct, trait, enum, etc.) should have. pub name: NameToImport, } @@ -70,10 +72,18 @@ pub enum NameToImport { impl NameToImport { pub fn exact_case_sensitive(s: String) -> NameToImport { + let s = match s.strip_prefix("r#") { + Some(s) => s.to_owned(), + None => s, + }; NameToImport::Exact(s, true) } pub fn fuzzy(s: String) -> NameToImport { + let s = match s.strip_prefix("r#") { + Some(s) => s.to_owned(), + None => s, + }; // unless all chars are lowercase, we do a case sensitive search let case_sensitive = s.chars().any(|c| c.is_uppercase()); NameToImport::Fuzzy(s, case_sensitive) @@ -350,21 +360,27 @@ fn path_applicable_imports( .take(DEFAULT_QUERY_SEARCH_LIMIT.inner()) .collect() } + // we have some unresolved qualifier that we search an import for + // The key here is that whatever we import must form a resolved path for the remainder of + // what follows + // FIXME: This doesn't handle visibility [first_qsegment, qualifier_rest @ ..] => items_locator::items_with_name( sema, current_crate, - NameToImport::Exact(first_qsegment.to_string(), true), + NameToImport::Exact(first_qsegment.as_str().to_owned(), true), AssocSearchMode::Exclude, ) .filter_map(|item| { - import_for_item( + // we found imports for `first_qsegment`, now we need to filter these imports by whether + // they result in resolving the rest of the path successfully + validate_resolvable( sema, scope, mod_path, + scope_filter, &path_candidate.name, item, qualifier_rest, - scope_filter, ) }) .take(DEFAULT_QUERY_SEARCH_LIMIT.inner()) @@ -372,14 +388,16 @@ fn path_applicable_imports( } } -fn import_for_item( +/// Validates and builds an import for `resolved_qualifier` if the `unresolved_qualifier` appended +/// to it resolves and there is a validate `candidate` after that. +fn validate_resolvable( sema: &Semantics<'_, RootDatabase>, scope: &SemanticsScope<'_>, mod_path: impl Fn(ItemInNs) -> Option<ModPath>, + scope_filter: impl Fn(ItemInNs) -> bool, candidate: &NameToImport, resolved_qualifier: ItemInNs, - unresolved_qualifier: &[SmolStr], - scope_filter: impl Fn(ItemInNs) -> bool, + unresolved_qualifier: &[Name], ) -> Option<LocatedImport> { let _p = tracing::info_span!("ImportAssets::import_for_item").entered(); @@ -410,8 +428,11 @@ fn import_for_item( module, candidate.clone(), AssocSearchMode::Exclude, + |it| match scope_filter(it) { + true => ControlFlow::Break(it), + false => ControlFlow::Continue(()), + }, ) - .find(|&it| scope_filter(it)) .map(|item| LocatedImport::new(import_path_candidate, resolved_qualifier, item)) } // FIXME @@ -709,7 +730,7 @@ fn path_import_candidate( if qualifier.first_qualifier().is_none_or(|it| sema.resolve_path(&it).is_none()) { let qualifier = qualifier .segments() - .map(|seg| seg.name_ref().map(|name| SmolStr::new(name.text()))) + .map(|seg| seg.name_ref().map(|name| Name::new_root(&name.text()))) .collect::<Option<Vec<_>>>()?; ImportCandidate::Path(PathImportCandidate { qualifier, name }) } else { diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs index 81604b55272..decb0ea9d8a 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use/tests.rs @@ -1244,8 +1244,8 @@ use ::ext::foo::Foo; fn check_with_config( path: &str, - ra_fixture_before: &str, - ra_fixture_after: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, config: &InsertUseConfig, ) { let (db, file_id, pos) = if ra_fixture_before.contains(CURSOR_MARKER) { @@ -1277,8 +1277,8 @@ fn check_with_config( fn check( path: &str, - ra_fixture_before: &str, - ra_fixture_after: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, granularity: ImportGranularity, ) { check_with_config( @@ -1295,19 +1295,35 @@ fn check( ) } -fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { +fn check_crate( + path: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate) } -fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { +fn check_module( + path: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module) } -fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { +fn check_none( + path: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item) } -fn check_one(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { +fn check_one( + path: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::One) } @@ -1330,7 +1346,7 @@ fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior assert_eq!(result.map(|u| u.to_string()), None); } -fn check_guess(ra_fixture: &str, expected: ImportGranularityGuess) { +fn check_guess(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: ImportGranularityGuess) { let syntax = ast::SourceFile::parse(ra_fixture, span::Edition::CURRENT).tree().syntax().clone(); let file = ImportScope::from(syntax).unwrap(); assert_eq!(super::guess_granularity_from_scope(&file), expected); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs index 7f66ea0c103..a2062f36d3f 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/items_locator.rs @@ -2,6 +2,8 @@ //! by its name and a few criteria. //! The main reason for this module to exist is the fact that project's items and dependencies' items //! are located in different caches, with different APIs. +use std::ops::ControlFlow; + use either::Either; use hir::{import_map, Crate, ItemInNs, Module, Semantics}; use limit::Limit; @@ -17,6 +19,7 @@ pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(100); pub use import_map::AssocSearchMode; +// FIXME: Do callbacks instead to avoid allocations. /// Searches for importable items with the given name in the crate and its dependencies. pub fn items_with_name<'a>( sema: &'a Semantics<'_, RootDatabase>, @@ -70,12 +73,13 @@ pub fn items_with_name<'a>( } /// Searches for importable items with the given name in the crate and its dependencies. -pub fn items_with_name_in_module<'a>( - sema: &'a Semantics<'_, RootDatabase>, +pub fn items_with_name_in_module<T>( + sema: &Semantics<'_, RootDatabase>, module: Module, name: NameToImport, assoc_item_search: AssocSearchMode, -) -> impl Iterator<Item = ItemInNs> + 'a { + mut cb: impl FnMut(ItemInNs) -> ControlFlow<T>, +) -> Option<T> { let _p = tracing::info_span!("items_with_name_in", name = name.text(), assoc_item_search = ?assoc_item_search, ?module) .entered(); @@ -107,14 +111,12 @@ pub fn items_with_name_in_module<'a>( local_query } }; - let mut local_results = Vec::new(); local_query.search(&[sema.db.module_symbols(module)], |local_candidate| { - local_results.push(match local_candidate.def { + cb(match local_candidate.def { hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def), def => ItemInNs::from(def), }) - }); - local_results.into_iter() + }) } fn find_items<'a>( @@ -142,7 +144,8 @@ fn find_items<'a>( local_results.push(match local_candidate.def { hir::ModuleDef::Macro(macro_def) => ItemInNs::Macros(macro_def), def => ItemInNs::from(def), - }) + }); + ControlFlow::<()>::Continue(()) }); local_results.into_iter().chain(external_importables) } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs index b3105e6524d..3a29232d331 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs @@ -260,23 +260,23 @@ impl From<hir::MacroKind> for SymbolKind { } } -impl From<hir::ModuleDefId> for SymbolKind { - fn from(it: hir::ModuleDefId) -> Self { +impl From<hir::ModuleDef> for SymbolKind { + fn from(it: hir::ModuleDef) -> Self { match it { - hir::ModuleDefId::ConstId(..) => SymbolKind::Const, - hir::ModuleDefId::EnumVariantId(..) => SymbolKind::Variant, - hir::ModuleDefId::FunctionId(..) => SymbolKind::Function, - hir::ModuleDefId::MacroId(hir::MacroId::ProcMacroId(..)) => SymbolKind::ProcMacro, - hir::ModuleDefId::MacroId(..) => SymbolKind::Macro, - hir::ModuleDefId::ModuleId(..) => SymbolKind::Module, - hir::ModuleDefId::StaticId(..) => SymbolKind::Static, - hir::ModuleDefId::AdtId(hir::AdtId::StructId(..)) => SymbolKind::Struct, - hir::ModuleDefId::AdtId(hir::AdtId::EnumId(..)) => SymbolKind::Enum, - hir::ModuleDefId::AdtId(hir::AdtId::UnionId(..)) => SymbolKind::Union, - hir::ModuleDefId::TraitId(..) => SymbolKind::Trait, - hir::ModuleDefId::TraitAliasId(..) => SymbolKind::TraitAlias, - hir::ModuleDefId::TypeAliasId(..) => SymbolKind::TypeAlias, - hir::ModuleDefId::BuiltinType(..) => SymbolKind::TypeAlias, + hir::ModuleDef::Const(..) => SymbolKind::Const, + hir::ModuleDef::Variant(..) => SymbolKind::Variant, + hir::ModuleDef::Function(..) => SymbolKind::Function, + hir::ModuleDef::Macro(mac) if mac.is_proc_macro() => SymbolKind::ProcMacro, + hir::ModuleDef::Macro(..) => SymbolKind::Macro, + hir::ModuleDef::Module(..) => SymbolKind::Module, + hir::ModuleDef::Static(..) => SymbolKind::Static, + hir::ModuleDef::Adt(hir::Adt::Struct(..)) => SymbolKind::Struct, + hir::ModuleDef::Adt(hir::Adt::Enum(..)) => SymbolKind::Enum, + hir::ModuleDef::Adt(hir::Adt::Union(..)) => SymbolKind::Union, + hir::ModuleDef::Trait(..) => SymbolKind::Trait, + hir::ModuleDef::TraitAlias(..) => SymbolKind::TraitAlias, + hir::ModuleDef::TypeAlias(..) => SymbolKind::TypeAlias, + hir::ModuleDef::BuiltinType(..) => SymbolKind::TypeAlias, } } } diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs index 1d1679c3ff8..42efbd68e33 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs @@ -134,6 +134,7 @@ impl Definition { FieldSource::Pos(_) => None, } } + Definition::Crate(_) => None, Definition::Module(module) => { let src = module.declaration_source(sema.db)?; let name = src.value.name()?; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs index 68199dd8711..a75aba137be 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs @@ -953,14 +953,19 @@ impl<'a> FindUsages<'a> { // Search for occurrences of the items name for offset in Self::match_indices(&text, finder, search_range) { - tree.token_at_offset(offset).for_each(|token| { - let Some(str_token) = ast::String::cast(token.clone()) else { return }; + let ret = tree.token_at_offset(offset).any(|token| { + let Some(str_token) = ast::String::cast(token.clone()) else { return false }; if let Some((range, Some(nameres))) = sema.check_for_format_args_template(token, offset) { - if self.found_format_args_ref(file_id, range, str_token, nameres, sink) {} + return self + .found_format_args_ref(file_id, range, str_token, nameres, sink); } + false }); + if ret { + return; + } for name in Self::find_nodes(sema, name, &tree, offset).filter_map(ast::NameLike::cast) diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs index 94d354d28e5..c94644eeb89 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs @@ -25,6 +25,7 @@ use std::{ fmt, hash::{Hash, Hasher}, mem, + ops::ControlFlow, }; use base_db::{ @@ -136,16 +137,13 @@ fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Ar // the module or crate indices for those in salsa unless we need to. .for_each(|module| symbol_collector.collect(module)); - let mut symbols = symbol_collector.finish(); - symbols.shrink_to_fit(); - Arc::new(SymbolIndex::new(symbols)) + Arc::new(SymbolIndex::new(symbol_collector.finish())) } fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc<SymbolIndex> { let _p = tracing::info_span!("module_symbols").entered(); - let symbols = SymbolCollector::collect_module(db.upcast(), module); - Arc::new(SymbolIndex::new(symbols)) + Arc::new(SymbolIndex::new(SymbolCollector::collect_module(db.upcast(), module))) } pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc<SymbolIndex>]> { @@ -222,13 +220,16 @@ pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol> { }; let mut res = vec![]; - query.search(&indices, |f| res.push(f.clone())); + query.search::<()>(&indices, |f| { + res.push(f.clone()); + ControlFlow::Continue(()) + }); res } #[derive(Default)] pub struct SymbolIndex { - symbols: Vec<FileSymbol>, + symbols: Box<[FileSymbol]>, map: fst::Map<Vec<u8>>, } @@ -253,10 +254,10 @@ impl Hash for SymbolIndex { } impl SymbolIndex { - fn new(mut symbols: Vec<FileSymbol>) -> SymbolIndex { + fn new(mut symbols: Box<[FileSymbol]>) -> SymbolIndex { fn cmp(lhs: &FileSymbol, rhs: &FileSymbol) -> Ordering { - let lhs_chars = lhs.name.chars().map(|c| c.to_ascii_lowercase()); - let rhs_chars = rhs.name.chars().map(|c| c.to_ascii_lowercase()); + let lhs_chars = lhs.name.as_str().chars().map(|c| c.to_ascii_lowercase()); + let rhs_chars = rhs.name.as_str().chars().map(|c| c.to_ascii_lowercase()); lhs_chars.cmp(rhs_chars) } @@ -316,11 +317,11 @@ impl SymbolIndex { } impl Query { - pub(crate) fn search<'sym>( + pub(crate) fn search<'sym, T>( self, indices: &'sym [Arc<SymbolIndex>], - cb: impl FnMut(&'sym FileSymbol), - ) { + cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>, + ) -> Option<T> { let _p = tracing::info_span!("symbol_index::Query::search").entered(); let mut op = fst::map::OpBuilder::new(); match self.mode { @@ -351,12 +352,12 @@ impl Query { } } - fn search_maps<'sym>( + fn search_maps<'sym, T>( &self, indices: &'sym [Arc<SymbolIndex>], mut stream: fst::map::Union<'_>, - mut cb: impl FnMut(&'sym FileSymbol), - ) { + mut cb: impl FnMut(&'sym FileSymbol) -> ControlFlow<T>, + ) -> Option<T> { let ignore_underscore_prefixed = !self.query.starts_with("__"); while let Some((_, indexed_values)) = stream.next() { for &IndexedValue { index, value } in indexed_values { @@ -377,15 +378,19 @@ impl Query { continue; } // Hide symbols that start with `__` unless the query starts with `__` - if ignore_underscore_prefixed && symbol.name.starts_with("__") { + let symbol_name = symbol.name.as_str(); + if ignore_underscore_prefixed && symbol_name.starts_with("__") { continue; } - if self.mode.check(&self.query, self.case_sensitive, &symbol.name) { - cb(symbol); + if self.mode.check(&self.query, self.case_sensitive, symbol_name) { + if let Some(b) = cb(symbol).break_value() { + return Some(b); + } } } } } + None } fn matches_assoc_mode(&self, is_trait_assoc_item: bool) -> bool { @@ -476,9 +481,9 @@ use Macro as ItemLikeMacro; use Macro as Trait; // overlay namespaces //- /b_mod.rs struct StructInModB; -use super::Macro as SuperItemLikeMacro; -use crate::b_mod::StructInModB as ThisStruct; -use crate::Trait as IsThisJustATrait; +pub(self) use super::Macro as SuperItemLikeMacro; +pub(self) use crate::b_mod::StructInModB as ThisStruct; +pub(self) use crate::Trait as IsThisJustATrait; "#, ); @@ -487,7 +492,7 @@ use crate::Trait as IsThisJustATrait; .into_iter() .map(|module_id| { let mut symbols = SymbolCollector::collect_module(&db, module_id); - symbols.sort_by_key(|it| it.name.clone()); + symbols.sort_by_key(|it| it.name.as_str().to_owned()); (module_id, symbols) }) .collect(); @@ -514,7 +519,7 @@ struct Duplicate; .into_iter() .map(|module_id| { let mut symbols = SymbolCollector::collect_module(&db, module_id); - symbols.sort_by_key(|it| it.name.clone()); + symbols.sort_by_key(|it| it.name.as_str().to_owned()); (module_id, symbols) }) .collect(); diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs index 365d726d2a9..557c95f704b 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs @@ -421,7 +421,7 @@ mod tests { use super::*; #[track_caller] - fn check(ra_fixture: &str, expected: &str) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &str) { let (db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture); let frange = FileRange { file_id, range: range_or_offset.into() }; diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt index 9d70942199c..535777dfcbe 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt +++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt @@ -631,7 +631,7 @@ def: Function( Function { id: FunctionId( - 3, + 2, ), }, ), @@ -664,7 +664,7 @@ def: Function( Function { id: FunctionId( - 2, + 1, ), }, ), @@ -794,7 +794,7 @@ def: Function( Function { id: FunctionId( - 1, + 3, ), }, ), @@ -879,12 +879,10 @@ [ FileSymbol { name: "IsThisJustATrait", - def: Macro( - Macro { - id: Macro2Id( - Macro2Id( - 0, - ), + def: Trait( + Trait { + id: TraitId( + 0, ), }, ), @@ -897,12 +895,12 @@ ), ptr: SyntaxNodePtr { kind: USE_TREE, - range: 111..143, + range: 141..173, }, name_ptr: AstPtr( SyntaxNodePtr { kind: NAME, - range: 127..143, + range: 157..173, }, ), }, @@ -911,40 +909,7 @@ is_assoc: false, }, FileSymbol { - name: "StructInModB", - def: Adt( - Struct( - Struct { - id: StructId( - 4, - ), - }, - ), - ), - loc: DeclarationLocation { - hir_file_id: EditionedFileId( - FileId( - 1, - ), - Edition2021, - ), - ptr: SyntaxNodePtr { - kind: STRUCT, - range: 0..20, - }, - name_ptr: AstPtr( - SyntaxNodePtr { - kind: NAME, - range: 7..19, - }, - ), - }, - container_name: None, - is_alias: false, - is_assoc: false, - }, - FileSymbol { - name: "SuperItemLikeMacro", + name: "IsThisJustATrait", def: Macro( Macro { id: Macro2Id( @@ -963,12 +928,12 @@ ), ptr: SyntaxNodePtr { kind: USE_TREE, - range: 25..59, + range: 141..173, }, name_ptr: AstPtr( SyntaxNodePtr { kind: NAME, - range: 41..59, + range: 157..173, }, ), }, @@ -977,7 +942,7 @@ is_assoc: false, }, FileSymbol { - name: "ThisStruct", + name: "StructInModB", def: Adt( Struct( Struct { @@ -995,13 +960,13 @@ Edition2021, ), ptr: SyntaxNodePtr { - kind: USE_TREE, - range: 65..105, + kind: STRUCT, + range: 0..20, }, name_ptr: AstPtr( SyntaxNodePtr { kind: NAME, - range: 95..105, + range: 7..19, }, ), }, @@ -1010,15 +975,15 @@ is_assoc: false, }, FileSymbol { - name: "ThisStruct", - def: Adt( - Struct( - Struct { - id: StructId( - 4, + name: "SuperItemLikeMacro", + def: Macro( + Macro { + id: Macro2Id( + Macro2Id( + 0, ), - }, - ), + ), + }, ), loc: DeclarationLocation { hir_file_id: EditionedFileId( @@ -1029,12 +994,12 @@ ), ptr: SyntaxNodePtr { kind: USE_TREE, - range: 65..105, + range: 35..69, }, name_ptr: AstPtr( SyntaxNodePtr { kind: NAME, - range: 95..105, + range: 51..69, }, ), }, diff --git a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs index 82aca50d039..0f67496d098 100644 --- a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs +++ b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs @@ -123,7 +123,9 @@ mod tests { use crate::RootDatabase; /// Creates analysis from a multi-file fixture, returns positions marked with $0. - pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { + pub(crate) fn position( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + ) -> (RootDatabase, FilePosition) { let change_fixture = ChangeFixture::parse(ra_fixture); let mut database = RootDatabase::default(); database.apply_change(change_fixture.change); @@ -133,7 +135,7 @@ mod tests { (database, FilePosition { file_id, offset }) } - fn check_trait(ra_fixture: &str, expect: Expect) { + fn check_trait(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, position) = position(ra_fixture); let sema = Semantics::new(&db); let file = sema.parse(position.file_id); @@ -147,7 +149,7 @@ mod tests { expect.assert_eq(&actual); } - fn check_missing_assoc(ra_fixture: &str, expect: Expect) { + fn check_missing_assoc(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (db, position) = position(ra_fixture); let sema = Semantics::new(&db); let file = sema.parse(position.file_id); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs index 2b59c1a22f6..7d62daf716c 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/generic_args_prohibited.rs @@ -604,4 +604,23 @@ fn bar() { "#, ); } + + #[test] + fn enum_variant_type_ns() { + check_diagnostics( + r#" +enum KvnDeserializerErr<I> { + UnexpectedKeyword { found: I, expected: I }, +} + +fn foo() { + let _x: KvnDeserializerErr<()> = + KvnDeserializerErr::<()>::UnexpectedKeyword { found: (), expected: () }; + let _x: KvnDeserializerErr<()> = + KvnDeserializerErr::<()>::UnexpectedKeyword::<()> { found: (), expected: () }; + // ^^^^^^ 💡 error: you can specify generic arguments on either the enum or the variant, but not both +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs index 4c0c685e550..96a368eb0ea 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs @@ -41,7 +41,7 @@ pub(crate) fn inactive_code( mod tests { use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig}; - pub(crate) fn check(ra_fixture: &str) { + pub(crate) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let config = DiagnosticsConfig { disabled: std::iter::once("unlinked-file".to_owned()).collect(), ..DiagnosticsConfig::test_sample() diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs index e177b72e4d4..99894fefef3 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs @@ -4,13 +4,13 @@ use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity}; // // This diagnostic is shown for macro expansion errors. -// Diagnostic: proc-macros-disabled +// Diagnostic: attribute-expansion-disabled // -// This diagnostic is shown for proc macros where proc macros have been disabled. +// This diagnostic is shown for attribute proc macros when attribute expansions have been disabled. // Diagnostic: proc-macro-disabled // -// This diagnostic is shown for proc macros that has been specifically disabled via `rust-analyzer.procMacro.ignored`. +// This diagnostic is shown for proc macros that have been specifically disabled via `rust-analyzer.procMacro.ignored`. pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic { // Use more accurate position if available. let display_range = ctx.resolve_precise_location(&d.node, d.precise_location); @@ -291,4 +291,30 @@ mod prim_never {} "#, ); } + + #[test] + fn no_stack_overflow_for_missing_binding() { + check_diagnostics( + r#" +#[macro_export] +macro_rules! boom { + ( + $($code:literal),+, + $(param: $param:expr,)? + ) => {{ + let _ = $crate::boom!(@param $($param)*); + }}; + (@param) => { () }; + (@param $param:expr) => { $param }; +} + +fn it_works() { + // NOTE: there is an error, but RA crashes before showing it + boom!("RAND", param: c7.clone()); + // ^^^^^ error: expected literal +} + + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs index 08e6e7dced9..0bf600e5dfa 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs @@ -26,7 +26,7 @@ mod tests { use test_utils::skip_slow_tests; #[track_caller] - fn check_diagnostics_no_bails(ra_fixture: &str) { + fn check_diagnostics_no_bails(#[rust_analyzer::rust_fixture] ra_fixture: &str) { cov_mark::check_count!(validate_match_bailed_out, 0); crate::tests::check_diagnostics(ra_fixture) } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs index e5d871975b6..0f126a1a656 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs @@ -399,4 +399,38 @@ fn f(s@m::Struct { "#, ) } + + #[test] + fn editions_between_macros() { + check_diagnostics( + r#" +//- /edition2015.rs crate:edition2015 edition:2015 +#[macro_export] +macro_rules! pass_expr_thorough { + ($e:expr) => { $e }; +} + +//- /edition2018.rs crate:edition2018 deps:edition2015 edition:2018 +async fn bar() {} +async fn foo() { + edition2015::pass_expr_thorough!(bar().await); +} + "#, + ); + check_diagnostics( + r#" +//- /edition2018.rs crate:edition2018 edition:2018 +pub async fn bar() {} +#[macro_export] +macro_rules! make_await { + () => { async { $crate::bar().await }; }; +} + +//- /edition2015.rs crate:edition2015 deps:edition2018 edition:2015 +fn foo() { + edition2018::make_await!(); +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs index f481365f2a5..4aff446de60 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs @@ -61,7 +61,7 @@ mod tests { }; #[track_caller] - pub(crate) fn check_diagnostics(ra_fixture: &str) { + pub(crate) fn check_diagnostics(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let mut config = DiagnosticsConfig::test_sample(); config.disabled.insert("inactive-code".to_owned()); config.disabled.insert("E0599".to_owned()); diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs index bfdda537405..56afb38cc81 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs @@ -1164,6 +1164,37 @@ struct Bar { } #[test] + fn trait_upcast_ok() { + check_diagnostics( + r#" +//- minicore: coerce_unsized +trait A: B {} +trait B {} + +fn test(a: &dyn A) -> &dyn B { + a +} +"#, + ); + } + + #[test] + fn trait_upcast_err() { + check_diagnostics( + r#" +//- minicore: coerce_unsized +trait A {} // `A` does not have `B` as a supertrait, so no upcast :c +trait B {} + +fn test(a: &dyn A) -> &dyn B { + a + //^ error: expected &dyn B, found &dyn A +} +"#, + ); + } + + #[test] fn return_no_value() { check_diagnostics_with_disabled( r#" diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs index ec74640a54d..fc2a7db7174 100644 --- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs @@ -1,5 +1,7 @@ #![allow(clippy::print_stderr)] +mod overly_long_real_world_cases; + use ide_db::{ assists::AssistResolveStrategy, base_db::SourceDatabase, LineIndexDatabase, RootDatabase, }; @@ -16,7 +18,10 @@ use crate::{DiagnosticsConfig, ExprFillDefaultMode, Severity}; /// * the first diagnostic fix trigger range touches the input cursor position /// * that the contents of the file containing the cursor match `after` after the diagnostic fix is applied #[track_caller] -pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { +pub(crate) fn check_fix( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { check_nth_fix(0, ra_fixture_before, ra_fixture_after); } /// Takes a multi-file input fixture with annotated cursor positions, @@ -24,14 +29,21 @@ pub(crate) fn check_fix(ra_fixture_before: &str, ra_fixture_after: &str) { /// * a diagnostic is produced /// * every diagnostic fixes trigger range touches the input cursor position /// * that the contents of the file containing the cursor match `after` after each diagnostic fix is applied -pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) { +pub(crate) fn check_fixes( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + ra_fixtures_after: Vec<&str>, +) { for (i, ra_fixture_after) in ra_fixtures_after.iter().enumerate() { check_nth_fix(i, ra_fixture_before, ra_fixture_after) } } #[track_caller] -fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { +fn check_nth_fix( + nth: usize, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { let mut config = DiagnosticsConfig::test_sample(); config.expr_fill_default = ExprFillDefaultMode::Default; check_nth_fix_with_config(config, nth, ra_fixture_before, ra_fixture_after) @@ -39,8 +51,8 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) { #[track_caller] pub(crate) fn check_fix_with_disabled( - ra_fixture_before: &str, - ra_fixture_after: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, disabled: impl Iterator<Item = String>, ) { let mut config = DiagnosticsConfig::test_sample(); @@ -53,8 +65,8 @@ pub(crate) fn check_fix_with_disabled( fn check_nth_fix_with_config( config: DiagnosticsConfig, nth: usize, - ra_fixture_before: &str, - ra_fixture_after: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, ) { let after = trim_indent(ra_fixture_after); @@ -93,14 +105,20 @@ fn check_nth_fix_with_config( assert_eq_text!(&after, &actual); } -pub(crate) fn check_fixes_unordered(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>) { +pub(crate) fn check_fixes_unordered( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + ra_fixtures_after: Vec<&str>, +) { for ra_fixture_after in ra_fixtures_after.iter() { check_has_fix(ra_fixture_before, ra_fixture_after) } } #[track_caller] -pub(crate) fn check_has_fix(ra_fixture_before: &str, ra_fixture_after: &str) { +pub(crate) fn check_has_fix( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { let after = trim_indent(ra_fixture_after); let (db, file_position) = RootDatabase::with_position(ra_fixture_before); @@ -143,7 +161,10 @@ pub(crate) fn check_has_fix(ra_fixture_before: &str, ra_fixture_after: &str) { } #[track_caller] -pub(crate) fn check_has_single_fix(ra_fixture_before: &str, ra_fixture_after: &str) { +pub(crate) fn check_has_single_fix( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, +) { let after = trim_indent(ra_fixture_after); let (db, file_position) = RootDatabase::with_position(ra_fixture_before); @@ -189,7 +210,7 @@ pub(crate) fn check_has_single_fix(ra_fixture_before: &str, ra_fixture_after: &s } /// Checks that there's a diagnostic *without* fix at `$0`. -pub(crate) fn check_no_fix(ra_fixture: &str) { +pub(crate) fn check_no_fix(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (db, file_position) = RootDatabase::with_position(ra_fixture); let diagnostic = super::full_diagnostics( &db, @@ -203,21 +224,27 @@ pub(crate) fn check_no_fix(ra_fixture: &str) { } #[track_caller] -pub(crate) fn check_diagnostics(ra_fixture: &str) { +pub(crate) fn check_diagnostics(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let mut config = DiagnosticsConfig::test_sample(); config.disabled.insert("inactive-code".to_owned()); check_diagnostics_with_config(config, ra_fixture) } #[track_caller] -pub(crate) fn check_diagnostics_with_disabled(ra_fixture: &str, disabled: &[&str]) { +pub(crate) fn check_diagnostics_with_disabled( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + disabled: &[&str], +) { let mut config = DiagnosticsConfig::test_sample(); config.disabled.extend(disabled.iter().map(|&s| s.to_owned())); check_diagnostics_with_config(config, ra_fixture) } #[track_caller] -pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixture: &str) { +pub(crate) fn check_diagnostics_with_config( + config: DiagnosticsConfig, + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) { let (db, files) = RootDatabase::with_many_files(ra_fixture); let mut annotations = files .iter() diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs new file mode 100644 index 00000000000..c6831d818aa --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests/overly_long_real_world_cases.rs @@ -0,0 +1,2726 @@ +//! Overly long excerpts of failures from real world cases, that I was too lazy to minimize. + +use crate::tests::check_diagnostics_with_disabled; + +#[test] +fn tracing_infinite_repeat() { + check_diagnostics_with_disabled( + r#" +//- /core.rs crate:core +#[rustc_builtin_macro] +#[macro_export] +macro_rules! concat { +($($e:expr),* $(,)?) => {{ /* compiler built-in */ }}; +} +#[rustc_builtin_macro] +#[macro_export] +macro_rules! file { +() => { + /* compiler built-in */ +}; +} +#[allow_internal_unsafe] +#[allow_internal_unstable(fmt_internals)] +#[rustc_builtin_macro] +#[macro_export] +macro_rules! format_args { +($fmt:expr) => {{ /* compiler built-in */ }}; +($fmt:expr, $($args:tt)*) => {{ /* compiler built-in */ }}; +} +#[rustc_builtin_macro] +#[macro_export] +macro_rules! line { +() => { + /* compiler built-in */ +}; +} + +//- /tracing_core.rs crate:tracing_core deps:core +#[macro_export] +macro_rules! identify_callsite { +($callsite:expr) => { + $crate::callsite::Identifier($callsite) +}; +} + +#[macro_export] +macro_rules! metadata { +( + name: $name:expr, + target: $target:expr, + level: $level:expr, + fields: $fields:expr, + callsite: $callsite:expr, + kind: $kind:expr +) => { + $crate::metadata! { + name: $name, + target: $target, + level: $level, + fields: $fields, + callsite: $callsite, + kind: $kind, + } +}; +( + name: $name:expr, + target: $target:expr, + level: $level:expr, + fields: $fields:expr, + callsite: $callsite:expr, + kind: $kind:expr, +) => { + $crate::metadata::Metadata::new( + $name, + $target, + $level, + $crate::__macro_support::Option::Some($crate::__macro_support::file!()), + $crate::__macro_support::Option::Some($crate::__macro_support::line!()), + $crate::__macro_support::Option::Some($crate::__macro_support::module_path!()), + $crate::field::FieldSet::new($fields, $crate::identify_callsite!($callsite)), + $kind, + ) +}; +} + +//- /tracing.rs crate:tracing deps:core,tracing_core +#[doc(hidden)] +pub mod __macro_support { +// Re-export the `core` functions that are used in macros. This allows +// a crate to be named `core` and avoid name clashes. +// See here: https://github.com/tokio-rs/tracing/issues/2761 +pub use core::{concat, file, format_args, iter::Iterator, line, option::Option}; +} + +#[macro_export] +macro_rules! span { +(target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr) => { + $crate::span!(target: $target, parent: $parent, $lvl, $name,) +}; +(target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr, $($fields:tt)*) => { + { + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::SPAN, + target: $target, + level: $lvl, + fields: $($fields)* + }; + let mut interest = $crate::subscriber::Interest::never(); + if $crate::level_enabled!($lvl) + && { interest = __CALLSITE.interest(); !interest.is_never() } + && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + { + let meta = __CALLSITE.metadata(); + // span with explicit parent + $crate::Span::child_of( + $parent, + meta, + &$crate::valueset!(meta.fields(), $($fields)*), + ) + } else { + let span = $crate::__macro_support::__disabled_span(__CALLSITE.metadata()); + $crate::if_log_enabled! { $lvl, { + span.record_all(&$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + }}; + span + } + } +}; +(target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => { + { + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::SPAN, + target: $target, + level: $lvl, + fields: $($fields)* + }; + let mut interest = $crate::subscriber::Interest::never(); + if $crate::level_enabled!($lvl) + && { interest = __CALLSITE.interest(); !interest.is_never() } + && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + { + let meta = __CALLSITE.metadata(); + // span with contextual parent + $crate::Span::new( + meta, + &$crate::valueset!(meta.fields(), $($fields)*), + ) + } else { + let span = $crate::__macro_support::__disabled_span(__CALLSITE.metadata()); + $crate::if_log_enabled! { $lvl, { + span.record_all(&$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + }}; + span + } + } +}; +(target: $target:expr, parent: $parent:expr, $lvl:expr, $name:expr) => { + $crate::span!(target: $target, parent: $parent, $lvl, $name,) +}; +(parent: $parent:expr, $lvl:expr, $name:expr, $($fields:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $lvl, + $name, + $($fields)* + ) +}; +(parent: $parent:expr, $lvl:expr, $name:expr) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $lvl, + $name, + ) +}; +(target: $target:expr, $lvl:expr, $name:expr, $($fields:tt)*) => { + $crate::span!( + target: $target, + $lvl, + $name, + $($fields)* + ) +}; +(target: $target:expr, $lvl:expr, $name:expr) => { + $crate::span!(target: $target, $lvl, $name,) +}; +($lvl:expr, $name:expr, $($fields:tt)*) => { + $crate::span!( + target: module_path!(), + $lvl, + $name, + $($fields)* + ) +}; +($lvl:expr, $name:expr) => { + $crate::span!( + target: module_path!(), + $lvl, + $name, + ) +}; +} + +#[macro_export] +macro_rules! trace_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::TRACE, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::trace_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::trace_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::TRACE, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::trace_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::TRACE, + $name, + $($field)* + ) +}; +($name:expr) => { $crate::trace_span!($name,) }; +} + +#[macro_export] +macro_rules! debug_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::DEBUG, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::debug_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::debug_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::DEBUG, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::debug_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::DEBUG, + $name, + $($field)* + ) +}; +($name:expr) => {$crate::debug_span!($name,)}; +} + +#[macro_export] +macro_rules! info_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::INFO, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::info_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::info_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::INFO, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::info_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::INFO, + $name, + $($field)* + ) +}; +($name:expr) => {$crate::info_span!($name,)}; +} + +#[macro_export] +macro_rules! warn_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::WARN, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::warn_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::warn_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::WARN, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::warn_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::WARN, + $name, + $($field)* + ) +}; +($name:expr) => {$crate::warn_span!($name,)}; +} + +#[macro_export] +macro_rules! error_span { +(target: $target:expr, parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + parent: $parent, + $crate::Level::ERROR, + $name, + $($field)* + ) +}; +(target: $target:expr, parent: $parent:expr, $name:expr) => { + $crate::error_span!(target: $target, parent: $parent, $name,) +}; +(parent: $parent:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + $name, + $($field)* + ) +}; +(parent: $parent:expr, $name:expr) => { + $crate::error_span!(parent: $parent, $name,) +}; +(target: $target:expr, $name:expr, $($field:tt)*) => { + $crate::span!( + target: $target, + $crate::Level::ERROR, + $name, + $($field)* + ) +}; +(target: $target:expr, $name:expr) => { + $crate::error_span!(target: $target, $name,) +}; +($name:expr, $($field:tt)*) => { + $crate::span!( + target: module_path!(), + $crate::Level::ERROR, + $name, + $($field)* + ) +}; +($name:expr) => {$crate::error_span!($name,)}; +} + +#[macro_export] +macro_rules! event { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::EVENT, + target: $target, + level: $lvl, + fields: $($fields)* + }; + + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + let meta = __CALLSITE.metadata(); + // event with explicit parent + $crate::Event::child_of( + $parent, + meta, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + name: $name, + target: $target, + parent: $parent, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $lvl, { $($k).+ = $($fields)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $lvl, { $($arg)+ }) +); + +// Name / target. +(name: $name:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::EVENT, + target: $target, + level: $lvl, + fields: $($fields)* + }; + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + let meta = __CALLSITE.metadata(); + // event with contextual parent + $crate::Event::dispatch( + meta, + &value_set + ); + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(name: $name:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + name: $name, + target: $target, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(name: $name:expr, target: $target:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(name: $name, target: $target, $lvl, { $($k).+ = $($fields)* }) +); +(name: $name:expr, target: $target:expr, $lvl:expr, $($arg:tt)+) => ( + $crate::event!(name: $name, target: $target, $lvl, { $($arg)+ }) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { + name: $crate::__macro_support::concat!( + "event ", + $crate::__macro_support::file!(), + ":", + $crate::__macro_support::line!() + ), + kind: $crate::metadata::Kind::EVENT, + target: $target, + level: $lvl, + fields: $($fields)* + }; + + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + let meta = __CALLSITE.metadata(); + // event with explicit parent + $crate::Event::child_of( + $parent, + meta, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(target: $target:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: $target, + parent: $parent, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(target: $target:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $lvl, { $($k).+ = $($fields)* }) +); +(target: $target:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => ( + $crate::event!(target: $target, parent: $parent, $lvl, { $($arg)+ }) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::EVENT, + target: module_path!(), + level: $lvl, + fields: $($fields)* + }; + + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && __CALLSITE.is_enabled(interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + let meta = __CALLSITE.metadata(); + // event with explicit parent + $crate::Event::child_of( + $parent, + meta, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(name: $name:expr, parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + name: $name, + parent: $parent, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(name: $name:expr, parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $lvl, { $($k).+ = $($fields)* }) +); +(name: $name:expr, parent: $parent:expr, $lvl:expr, $($arg:tt)+) => ( + $crate::event!(name: $name, parent: $parent, $lvl, { $($arg)+ }) +); + +// Name. +(name: $name:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::__macro_support::MacroCallsite = $crate::callsite2! { + name: $name, + kind: $crate::metadata::Kind::EVENT, + target: module_path!(), + level: $lvl, + fields: $($fields)* + }; + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + let meta = __CALLSITE.metadata(); + // event with contextual parent + $crate::Event::dispatch( + meta, + &value_set + ); + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(name: $name:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + name: $name, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(name: $name:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(name: $name, $lvl, { $($k).+ = $($fields)* }) +); +(name: $name:expr, $lvl:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $lvl, { $($arg)+ }) +); + +// Target. +(target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { + name: $crate::__macro_support::concat!( + "event ", + $crate::__macro_support::file!(), + ":", + $crate::__macro_support::line!() + ), + kind: $crate::metadata::Kind::EVENT, + target: $target, + level: $lvl, + fields: $($fields)* + }; + let enabled = $crate::level_enabled!($lvl) && { + let interest = __CALLSITE.interest(); + !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) + }; + if enabled { + (|value_set: $crate::field::ValueSet| { + let meta = __CALLSITE.metadata(); + // event with contextual parent + $crate::Event::dispatch( + meta, + &value_set + ); + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &value_set + ); + })($crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*)); + } else { + $crate::__tracing_log!( + $lvl, + __CALLSITE, + &$crate::valueset!(__CALLSITE.metadata().fields(), $($fields)*) + ); + } +}); +(target: $target:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: $target, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(target: $target:expr, $lvl:expr, $($k:ident).+ = $($fields:tt)* ) => ( + $crate::event!(target: $target, $lvl, { $($k).+ = $($fields)* }) +); +(target: $target:expr, $lvl:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $lvl, { $($arg)+ }) +); + +// Parent. +(parent: $parent:expr, $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +(parent: $parent:expr, $lvl:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $lvl, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $lvl:expr, $($arg:tt)+ ) => ( + $crate::event!(target: module_path!(), parent: $parent, $lvl, { $($arg)+ }) +); + +// ... +( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $lvl, + { message = $crate::__macro_support::format_args!($($arg)+), $($fields)* } + ) +); +( $lvl:expr, { $($fields:tt)* }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $lvl, + { message = format_args!($($arg)+), $($fields)* } + ) +); +($lvl:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $lvl, + { $($k).+ = $($field)*} + ) +); +($lvl:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $lvl, + { $($k).+, $($field)*} + ) +); +($lvl:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $lvl, + { ?$($k).+, $($field)*} + ) +); +($lvl:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $lvl, + { %$($k).+, $($field)*} + ) +); +($lvl:expr, ?$($k:ident).+) => ( + $crate::event!($lvl, ?$($k).+,) +); +($lvl:expr, %$($k:ident).+) => ( + $crate::event!($lvl, %$($k).+,) +); +($lvl:expr, $($k:ident).+) => ( + $crate::event!($lvl, $($k).+,) +); +( $lvl:expr, $($arg:tt)+ ) => ( + $crate::event!(target: module_path!(), $lvl, { $($arg)+ }) +); +} + +#[macro_export] +macro_rules! event_enabled { +($($rest:tt)*)=> ( + $crate::enabled!(kind: $crate::metadata::Kind::EVENT, $($rest)*) +) +} + +#[macro_export] +macro_rules! span_enabled { +($($rest:tt)*)=> ( + $crate::enabled!(kind: $crate::metadata::Kind::SPAN, $($rest)*) +) +} + +#[macro_export] +macro_rules! enabled { +(kind: $kind:expr, target: $target:expr, $lvl:expr, { $($fields:tt)* } )=> ({ + if $crate::level_enabled!($lvl) { + use $crate::__macro_support::Callsite as _; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite2! { + name: $crate::__macro_support::concat!( + "enabled ", + $crate::__macro_support::file!(), + ":", + $crate::__macro_support::line!() + ), + kind: $kind.hint(), + target: $target, + level: $lvl, + fields: $($fields)* + }; + let interest = __CALLSITE.interest(); + if !interest.is_never() && $crate::__macro_support::__is_enabled(__CALLSITE.metadata(), interest) { + let meta = __CALLSITE.metadata(); + $crate::dispatcher::get_default(|current| current.enabled(meta)) + } else { + false + } + } else { + false + } +}); +// Just target and level +(kind: $kind:expr, target: $target:expr, $lvl:expr ) => ( + $crate::enabled!(kind: $kind, target: $target, $lvl, { }) +); +(target: $target:expr, $lvl:expr ) => ( + $crate::enabled!(kind: $crate::metadata::Kind::HINT, target: $target, $lvl, { }) +); + +// These four cases handle fields with no values +(kind: $kind:expr, target: $target:expr, $lvl:expr, $($field:tt)*) => ( + $crate::enabled!( + kind: $kind, + target: $target, + $lvl, + { $($field)*} + ) +); +(target: $target:expr, $lvl:expr, $($field:tt)*) => ( + $crate::enabled!( + kind: $crate::metadata::Kind::HINT, + target: $target, + $lvl, + { $($field)*} + ) +); + +// Level and field case +(kind: $kind:expr, $lvl:expr, $($field:tt)*) => ( + $crate::enabled!( + kind: $kind, + target: module_path!(), + $lvl, + { $($field)*} + ) +); + +// Simplest `enabled!` case +(kind: $kind:expr, $lvl:expr) => ( + $crate::enabled!(kind: $kind, target: module_path!(), $lvl, { }) +); +($lvl:expr) => ( + $crate::enabled!(kind: $crate::metadata::Kind::HINT, target: module_path!(), $lvl, { }) +); + +// Fallthrough from above +($lvl:expr, $($field:tt)*) => ( + $crate::enabled!( + kind: $crate::metadata::Kind::HINT, + target: module_path!(), + $lvl, + { $($field)*} + ) +); +} + +#[macro_export] +macro_rules! trace { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::TRACE, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::TRACE, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::TRACE, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::TRACE, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::TRACE, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::TRACE, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::TRACE, + $($arg)+ + ) +); +} + +#[macro_export] +macro_rules! debug { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::DEBUG, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::DEBUG, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::DEBUG, + $($arg)+ + ) +); +} + +#[macro_export] +macro_rules! info { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::INFO, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::INFO, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::INFO, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::INFO, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::INFO, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::INFO, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::INFO, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::INFO, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::INFO, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::INFO, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::INFO, + $($arg)+ + ) +); +} + +#[macro_export] +macro_rules! warn { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::WARN, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::WARN, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::WARN, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::WARN, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::WARN, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::WARN, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::WARN, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::WARN, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::WARN, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::WARN, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::WARN, + $($arg)+ + ) +); +} + +#[macro_export] +macro_rules! error { +// Name / target / parent. +(name: $name:expr, target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+) +); + +// Name / target. +(name: $name:expr, target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(name: $name:expr, target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(name: $name:expr, target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, target: $target, $crate::Level::ERROR, {}, $($arg)+) +); + +// Target / parent. +(target: $target:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(target: $target:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(target: $target:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, parent: $parent, $crate::Level::ERROR, {}, $($arg)+) +); + +// Name / parent. +(name: $name:expr, parent: $parent:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(name: $name:expr, parent: $parent:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(name: $name:expr, parent: $parent:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, parent: $parent, $crate::Level::ERROR, {}, $($arg)+) +); + +// Name. +(name: $name:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(name: $name:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(name: $name:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(name: $name:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(name: $name:expr, $($arg:tt)+ ) => ( + $crate::event!(name: $name, $crate::Level::ERROR, {}, $($arg)+) +); + +// Target. +(target: $target:expr, { $($field:tt)* }, $($arg:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, { $($field)* }, $($arg)*) +); +(target: $target:expr, $($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, { $($k).+ $($field)* }) +); +(target: $target:expr, ?$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, { ?$($k).+ $($field)* }) +); +(target: $target:expr, %$($k:ident).+ $($field:tt)* ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, { %$($k).+ $($field)* }) +); +(target: $target:expr, $($arg:tt)+ ) => ( + $crate::event!(target: $target, $crate::Level::ERROR, {}, $($arg)+) +); + +// Parent. +(parent: $parent:expr, { $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { $($field)+ }, + $($arg)+ + ) +); +(parent: $parent:expr, $($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { $($k).+ = $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { ?$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { %$($k).+ = $($field)*} + ) +); +(parent: $parent:expr, $($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { $($k).+, $($field)*} + ) +); +(parent: $parent:expr, ?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { ?$($k).+, $($field)*} + ) +); +(parent: $parent:expr, %$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + { %$($k).+, $($field)*} + ) +); +(parent: $parent:expr, $($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + parent: $parent, + $crate::Level::ERROR, + {}, + $($arg)+ + ) +); + +// ... +({ $($field:tt)+ }, $($arg:tt)+ ) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { $($field)+ }, + $($arg)+ + ) +); +($($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { $($k).+ = $($field)*} + ) +); +(?$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { ?$($k).+ = $($field)*} + ) +); +(%$($k:ident).+ = $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { %$($k).+ = $($field)*} + ) +); +($($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { $($k).+, $($field)*} + ) +); +(?$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { ?$($k).+, $($field)*} + ) +); +(%$($k:ident).+, $($field:tt)*) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { %$($k).+, $($field)*} + ) +); +(?$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { ?$($k).+ } + ) +); +(%$($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { %$($k).+ } + ) +); +($($k:ident).+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + { $($k).+ } + ) +); +($($arg:tt)+) => ( + $crate::event!( + target: module_path!(), + $crate::Level::ERROR, + $($arg)+ + ) +); +} + +#[doc(hidden)] +#[macro_export] +macro_rules! callsite { +(name: $name:expr, kind: $kind:expr, fields: $($fields:tt)*) => {{ + $crate::callsite! { + name: $name, + kind: $kind, + target: module_path!(), + level: $crate::Level::TRACE, + fields: $($fields)* + } +}}; +( + name: $name:expr, + kind: $kind:expr, + level: $lvl:expr, + fields: $($fields:tt)* +) => {{ + $crate::callsite! { + name: $name, + kind: $kind, + target: module_path!(), + level: $lvl, + fields: $($fields)* + } +}}; +( + name: $name:expr, + kind: $kind:expr, + target: $target:expr, + level: $lvl:expr, + fields: $($fields:tt)* +) => {{ + static META: $crate::Metadata<'static> = { + $crate::metadata! { + name: $name, + target: $target, + level: $lvl, + fields: $crate::fieldset!( $($fields)* ), + callsite: &__CALLSITE, + kind: $kind, + } + }; + static __CALLSITE: $crate::callsite::DefaultCallsite = $crate::callsite::DefaultCallsite::new(&META); + __CALLSITE.register(); + &__CALLSITE +}}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! callsite2 { +(name: $name:expr, kind: $kind:expr, fields: $($fields:tt)*) => {{ + $crate::callsite2! { + name: $name, + kind: $kind, + target: module_path!(), + level: $crate::Level::TRACE, + fields: $($fields)* + } +}}; +( + name: $name:expr, + kind: $kind:expr, + level: $lvl:expr, + fields: $($fields:tt)* +) => {{ + $crate::callsite2! { + name: $name, + kind: $kind, + target: module_path!(), + level: $lvl, + fields: $($fields)* + } +}}; +( + name: $name:expr, + kind: $kind:expr, + target: $target:expr, + level: $lvl:expr, + fields: $($fields:tt)* +) => {{ + static META: $crate::Metadata<'static> = { + $crate::metadata! { + name: $name, + target: $target, + level: $lvl, + fields: $crate::fieldset!( $($fields)* ), + callsite: &__CALLSITE, + kind: $kind, + } + }; + $crate::callsite::DefaultCallsite::new(&META) +}}; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! level_enabled { +($lvl:expr) => { + $lvl <= $crate::level_filters::STATIC_MAX_LEVEL + && $lvl <= $crate::level_filters::LevelFilter::current() +}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! valueset { + +// === base case === +(@ { $(,)* $($val:expr),* $(,)* }, $next:expr $(,)*) => { + &[ $($val),* ] +}; + +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$($k).+ as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$($k).+) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$($k).+) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = ?$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = %$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+ = $val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $($k:ident).+) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$($k).+ as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, ?$($k:ident).+) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$($k).+) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, %$($k:ident).+) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$($k).+) as &dyn Value)) }, + $next, + ) +}; + +// Handle literal names +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = ?$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&debug(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = %$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&display(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, $k:literal = $val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, $crate::__macro_support::Option::Some(&$val as &dyn Value)) }, + $next, + ) +}; + +// Handle constant names +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = ?$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = %$val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = $val:expr, $($rest:tt)*) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&$val as &dyn Value)) }, + $next, + $($rest)* + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = ?$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&debug(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = %$val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&display(&$val) as &dyn Value)) }, + $next, + ) +}; +(@ { $(,)* $($out:expr),* }, $next:expr, { $k:expr } = $val:expr) => { + $crate::valueset!( + @ { $($out),*, (&$next, Some(&$val as &dyn Value)) }, + $next, + ) +}; + +(@ { $(,)* $($out:expr),* }, $next:expr, $($rest:tt)+) => { + $crate::valueset!(@ { (&$next, $crate::__macro_support::Option::Some(&$crate::__macro_support::format_args!($($rest)+) as &dyn Value)), $($out),* }, $next, ) +}; + +($fields:expr, $($kvs:tt)+) => { + { + #[allow(unused_imports)] + use $crate::field::{debug, display, Value}; + let mut iter = $fields.iter(); + $fields.value_set($crate::valueset!( + @ { }, + $crate::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"), + $($kvs)+ + )) + } +}; +($fields:expr,) => { + { + $fields.value_set(&[]) + } +}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! fieldset { +(@ { $(,)* $($out:expr),* $(,)* } $(,)*) => { + &[ $($out),* ] +}; + +(@ { $(,)* $($out:expr),* } $($k:ident).+ = ?$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $($k:ident).+ = %$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $($k:ident).+ = $val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } ?$($k:ident).+, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } %$($k:ident).+, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $($k:ident).+, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $crate::__tracing_stringify!($($k).+) } $($rest)*) +}; + +// Handle literal names +(@ { $(,)* $($out:expr),* } $k:literal = ?$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $k:literal = %$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } $k:literal = $val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; + +// Handle constant names +(@ { $(,)* $($out:expr),* } { $k:expr } = ?$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } { $k:expr } = %$val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; +(@ { $(,)* $($out:expr),* } { $k:expr } = $val:expr, $($rest:tt)*) => { + $crate::fieldset!(@ { $($out),*, $k } $($rest)*) +}; + +(@ { $(,)* $($out:expr),* } $($rest:tt)+) => { + $crate::fieldset!(@ { "message", $($out),*, }) +}; + +($($args:tt)*) => { + $crate::fieldset!(@ { } $($args)*,) +}; + +} + +#[cfg(feature = "log")] +#[doc(hidden)] +#[macro_export] +macro_rules! level_to_log { +($level:expr) => { + match $level { + $crate::Level::ERROR => $crate::log::Level::Error, + $crate::Level::WARN => $crate::log::Level::Warn, + $crate::Level::INFO => $crate::log::Level::Info, + $crate::Level::DEBUG => $crate::log::Level::Debug, + _ => $crate::log::Level::Trace, + } +}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __tracing_stringify { +($($t:tt)*) => { + stringify!($($t)*) +}; +} + +#[cfg(not(feature = "log"))] +#[doc(hidden)] +#[macro_export] +macro_rules! __tracing_log { +($level:expr, $callsite:expr, $value_set:expr) => {}; +} + +#[cfg(feature = "log")] +#[doc(hidden)] +#[macro_export] +macro_rules! __tracing_log { +($level:expr, $callsite:expr, $value_set:expr) => { + $crate::if_log_enabled! { $level, { + use $crate::log; + let level = $crate::level_to_log!($level); + if level <= log::max_level() { + let meta = $callsite.metadata(); + let log_meta = log::Metadata::builder() + .level(level) + .target(meta.target()) + .build(); + let logger = log::logger(); + if logger.enabled(&log_meta) { + $crate::__macro_support::__tracing_log(meta, logger, log_meta, $value_set) + } + } + }} +}; +} + +#[cfg(not(feature = "log"))] +#[doc(hidden)] +#[macro_export] +macro_rules! if_log_enabled { +($lvl:expr, $e:expr;) => { + $crate::if_log_enabled! { $lvl, $e } +}; +($lvl:expr, $if_log:block) => { + $crate::if_log_enabled! { $lvl, $if_log else {} } +}; +($lvl:expr, $if_log:block else $else_block:block) => { + $else_block +}; +} + +#[cfg(all(feature = "log", not(feature = "log-always")))] +#[doc(hidden)] +#[macro_export] +macro_rules! if_log_enabled { +($lvl:expr, $e:expr;) => { + $crate::if_log_enabled! { $lvl, $e } +}; +($lvl:expr, $if_log:block) => { + $crate::if_log_enabled! { $lvl, $if_log else {} } +}; +($lvl:expr, $if_log:block else $else_block:block) => { + if $crate::level_to_log!($lvl) <= $crate::log::STATIC_MAX_LEVEL { + if !$crate::dispatcher::has_been_set() { + $if_log + } else { + $else_block + } + } else { + $else_block + } +}; +} + +#[cfg(all(feature = "log", feature = "log-always"))] +#[doc(hidden)] +#[macro_export] +macro_rules! if_log_enabled { +($lvl:expr, $e:expr;) => { + $crate::if_log_enabled! { $lvl, $e } +}; +($lvl:expr, $if_log:block) => { + $crate::if_log_enabled! { $lvl, $if_log else {} } +}; +($lvl:expr, $if_log:block else $else_block:block) => { + if $crate::level_to_log!($lvl) <= $crate::log::STATIC_MAX_LEVEL { + #[allow(unused_braces)] + $if_log + } else { + $else_block + } +}; +} + +//- /lib.rs crate:ra_test_fixture deps:tracing +fn foo() { +tracing::error!(); +} + "#, + &["E0432", "inactive-code", "unresolved-macro-call", "syntax-error", "macro-error"], + ); +} diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs index 6a4e5ba290e..18f866eb9fc 100644 --- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs +++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs @@ -220,7 +220,11 @@ mod tests { location: AnnotationLocation::AboveName, }; - fn check_with_config(ra_fixture: &str, expect: Expect, config: &AnnotationConfig) { + fn check_with_config( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, + config: &AnnotationConfig, + ) { let (analysis, file_id) = fixture::file(ra_fixture); let annotations: Vec<Annotation> = analysis @@ -233,7 +237,7 @@ mod tests { expect.assert_debug_eq(&annotations); } - fn check(ra_fixture: &str, expect: Expect) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { check_with_config(ra_fixture, expect, &DEFAULT_CONFIG); } diff --git a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs index 8066894cd83..afd6f740c42 100644 --- a/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs +++ b/src/tools/rust-analyzer/crates/ide/src/call_hierarchy.rs @@ -173,7 +173,7 @@ mod tests { fn check_hierarchy( exclude_tests: bool, - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, expected_nav: Expect, expected_incoming: Expect, expected_outgoing: Expect, diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs index 72fcac54177..bc9843f3f35 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs @@ -199,6 +199,7 @@ pub(crate) fn resolve_doc_path_for_def( ) -> Option<Definition> { match def { Definition::Module(it) => it.resolve_doc_path(db, link, ns), + Definition::Crate(it) => it.resolve_doc_path(db, link, ns), Definition::Function(it) => it.resolve_doc_path(db, link, ns), Definition::Adt(it) => it.resolve_doc_path(db, link, ns), Definition::Variant(it) => it.resolve_doc_path(db, link, ns), @@ -594,6 +595,7 @@ fn filename_and_frag_for_def( Adt::Enum(e) => format!("enum.{}.html", e.name(db).unescaped().display(db.upcast())), Adt::Union(u) => format!("union.{}.html", u.name(db).unescaped().display(db.upcast())), }, + Definition::Crate(_) => String::from("index.html"), Definition::Module(m) => match m.name(db) { // `#[doc(keyword = "...")]` is internal used only by rust compiler Some(name) => { diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs index fe91c81a615..d7291c4b9f3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs @@ -16,7 +16,7 @@ use crate::{ }; fn check_external_docs( - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, target_dir: Option<&str>, expect_web_url: Option<Expect>, expect_local_url: Option<Expect>, @@ -41,7 +41,7 @@ fn check_external_docs( } } -fn check_rewrite(ra_fixture: &str, expect: Expect) { +fn check_rewrite(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let sema = &Semantics::new(&*analysis.db); let (cursor_def, docs) = def_under_cursor(sema, &position); @@ -49,7 +49,7 @@ fn check_rewrite(ra_fixture: &str, expect: Expect) { expect.assert_eq(&res) } -fn check_doc_links(ra_fixture: &str) { +fn check_doc_links(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let key_fn = |&(FileRange { file_id, range }, _): &_| (file_id, range.start()); let (analysis, position, mut expected) = fixture::annotations(ra_fixture); diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs index e028c5ff0cb..0ad894427b2 100644 --- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs +++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs @@ -296,7 +296,7 @@ mod tests { use crate::fixture; #[track_caller] - fn check(ra_fixture: &str, expect: Expect) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, pos) = fixture::position(ra_fixture); let expansion = analysis.expand_macro(pos).unwrap().unwrap(); let actual = format!("{}\n{}", expansion.name, expansion.expansion); diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs index 5ef65c209ca..50977ee840c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs +++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs @@ -257,7 +257,7 @@ mod tests { use super::*; - fn check(ra_fixture: &str, expect: Expect) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let file = SourceFile::parse(ra_fixture, span::Edition::CURRENT).ok().unwrap(); let structure = file_structure(&file); expect.assert_debug_eq(&structure) diff --git a/src/tools/rust-analyzer/crates/ide/src/fixture.rs b/src/tools/rust-analyzer/crates/ide/src/fixture.rs index b16511072bd..a0612f48d37 100644 --- a/src/tools/rust-analyzer/crates/ide/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/ide/src/fixture.rs @@ -5,7 +5,7 @@ use test_utils::{extract_annotations, RangeOrOffset}; use crate::{Analysis, AnalysisHost, FileId, FilePosition, FileRange}; /// Creates analysis for a single file. -pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) { +pub(crate) fn file(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Analysis, FileId) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); host.db.enable_proc_attr_macros(); @@ -14,7 +14,9 @@ pub(crate) fn file(ra_fixture: &str) -> (Analysis, FileId) { } /// Creates analysis from a multi-file fixture, returns positions marked with $0. -pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { +pub(crate) fn position( + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) -> (Analysis, FilePosition) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); host.db.enable_proc_attr_macros(); @@ -25,7 +27,7 @@ pub(crate) fn position(ra_fixture: &str) -> (Analysis, FilePosition) { } /// Creates analysis for a single file, returns range marked with a pair of $0. -pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { +pub(crate) fn range(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Analysis, FileRange) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); host.db.enable_proc_attr_macros(); @@ -36,7 +38,9 @@ pub(crate) fn range(ra_fixture: &str) -> (Analysis, FileRange) { } /// Creates analysis for a single file, returns range marked with a pair of $0 or a position marked with $0. -pub(crate) fn range_or_position(ra_fixture: &str) -> (Analysis, FileId, RangeOrOffset) { +pub(crate) fn range_or_position( + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) -> (Analysis, FileId, RangeOrOffset) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); host.db.enable_proc_attr_macros(); @@ -46,7 +50,9 @@ pub(crate) fn range_or_position(ra_fixture: &str) -> (Analysis, FileId, RangeOrO } /// Creates analysis from a multi-file fixture, returns positions marked with $0. -pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(FileRange, String)>) { +pub(crate) fn annotations( + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) -> (Analysis, FilePosition, Vec<(FileRange, String)>) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); host.db.enable_proc_attr_macros(); @@ -69,7 +75,9 @@ pub(crate) fn annotations(ra_fixture: &str) -> (Analysis, FilePosition, Vec<(Fil } /// Creates analysis from a multi-file fixture with annotations without $0 -pub(crate) fn annotations_without_marker(ra_fixture: &str) -> (Analysis, Vec<(FileRange, String)>) { +pub(crate) fn annotations_without_marker( + #[rust_analyzer::rust_fixture] ra_fixture: &str, +) -> (Analysis, Vec<(FileRange, String)>) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); host.db.enable_proc_attr_macros(); diff --git a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs index c1b7693a650..e5a94ff9fe9 100755 --- a/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs +++ b/src/tools/rust-analyzer/crates/ide/src/folding_ranges.rs @@ -286,7 +286,7 @@ mod tests { use super::*; - fn check(ra_fixture: &str) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (ranges, text) = extract_tags(ra_fixture, "fold"); let parse = SourceFile::parse(&text, span::Edition::CURRENT); diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs index 7b6a5ef13e5..3742edc8db8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs @@ -83,7 +83,7 @@ mod tests { use crate::fixture; - fn check(ra_fixture: &str) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); let navs = analysis .goto_declaration(position) diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs index 6c66907ec3e..f804cc36772 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs @@ -81,6 +81,10 @@ pub(crate) fn goto_definition( return Some(RangeInfo::new(original_token.text_range(), navs)); } + if let Some(navs) = find_definition_for_known_blanket_dual_impls(sema, &original_token) { + return Some(RangeInfo::new(original_token.text_range(), navs)); + } + let navs = sema .descend_into_macros_no_opaque(original_token.clone()) .into_iter() @@ -125,6 +129,18 @@ pub(crate) fn goto_definition( Some(RangeInfo::new(original_token.text_range(), navs)) } +// If the token is into(), try_into(), parse(), search the definition of From, TryFrom, FromStr. +fn find_definition_for_known_blanket_dual_impls( + sema: &Semantics<'_, RootDatabase>, + original_token: &SyntaxToken, +) -> Option<Vec<NavigationTarget>> { + let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?; + let target_method = sema.resolve_known_blanket_dual_impls(&method_call)?; + + let def = Definition::from(target_method); + Some(def_to_nav(sema.db, def)) +} + fn try_lookup_include_path( sema: &Semantics<'_, RootDatabase>, token: ast::String, @@ -424,7 +440,7 @@ mod tests { use syntax::SmolStr; #[track_caller] - fn check(ra_fixture: &str) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; @@ -443,14 +459,14 @@ mod tests { assert_eq!(expected, navs); } - fn check_unresolved(ra_fixture: &str) { + fn check_unresolved(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {navs:?}") } - fn check_name(expected_name: &str, ra_fixture: &str) { + fn check_name(expected_name: &str, #[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, _) = fixture::annotations(ra_fixture); let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info; assert!(navs.len() < 2, "expected single navigation target but encountered {}", navs.len()); @@ -3022,4 +3038,150 @@ fn foo() { "#, ); } + #[test] + fn into_call_to_from_definition() { + check( + r#" +//- minicore: from +struct A; + +struct B; + +impl From<A> for B { + fn from(value: A) -> Self { + //^^^^ + B + } +} + +fn f() { + let a = A; + let b: B = a.into$0(); +} + "#, + ); + } + + #[test] + fn into_call_to_from_definition_with_trait_bounds() { + check( + r#" +//- minicore: from, iterator +struct A; + +impl<T> From<T> for A +where + T: IntoIterator<Item = i64>, +{ + fn from(value: T) -> Self { + //^^^^ + A + } +} + +fn f() { + let a: A = [1, 2, 3].into$0(); +} + "#, + ); + } + + #[test] + fn goto_into_definition_if_exists() { + check( + r#" +//- minicore: from +struct A; + +struct B; + +impl Into<B> for A { + fn into(self) -> B { + //^^^^ + B + } +} + +fn f() { + let a = A; + let b: B = a.into$0(); +} + "#, + ); + } + + #[test] + fn try_into_call_to_try_from_definition() { + check( + r#" +//- minicore: from +struct A; + +struct B; + +impl TryFrom<A> for B { + type Error = String; + + fn try_from(value: A) -> Result<Self, Self::Error> { + //^^^^^^^^ + Ok(B) + } +} + +fn f() { + let a = A; + let b: Result<B, _> = a.try_into$0(); +} + "#, + ); + } + + #[test] + fn goto_try_into_definition_if_exists() { + check( + r#" +//- minicore: from +struct A; + +struct B; + +impl TryInto<B> for A { + type Error = String; + + fn try_into(self) -> Result<B, Self::Error> { + //^^^^^^^^ + Ok(B) + } +} + +fn f() { + let a = A; + let b: Result<B, _> = a.try_into$0(); +} + "#, + ); + } + + #[test] + fn parse_call_to_from_str_definition() { + check( + r#" +//- minicore: from, str +struct A; + +impl FromStr for A { + type Error = String; + + fn from_str(value: &str) -> Result<Self, Self::Error> { + //^^^^^^^^ + Ok(A) + } +} + +fn f() { + let a: Result<A, _> = "aaaaaa".parse$0(); +} + "#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs index 04da1f67e95..e926378367e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs @@ -129,7 +129,7 @@ mod tests { use crate::fixture; - fn check(ra_fixture: &str) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); let navs = analysis.goto_implementation(position).unwrap().unwrap().info; diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs index c7ebd9a3531..2610d6c8863 100644 --- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs +++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs @@ -24,9 +24,10 @@ pub(crate) fn goto_type_definition( let file: ast::SourceFile = sema.parse_guess_edition(file_id); let token: SyntaxToken = pick_best_token(file.syntax().token_at_offset(offset), |kind| match kind { - IDENT | INT_NUMBER | T![self] => 2, + IDENT | INT_NUMBER | T![self] => 3, kind if kind.is_trivia() => 0, - _ => 1, + T![;] => 1, + _ => 2, })?; let mut res = Vec::new(); @@ -118,7 +119,7 @@ mod tests { use crate::fixture; - fn check(ra_fixture: &str) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); let navs = analysis.goto_type_definition(position).unwrap().unwrap().info; assert!(!navs.is_empty(), "navigation is empty"); diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs index 4002cbebad6..612bc36f628 100644 --- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs +++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs @@ -684,12 +684,15 @@ mod tests { }; #[track_caller] - fn check(ra_fixture: &str) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_with_config(ra_fixture, ENABLED_CONFIG); } #[track_caller] - fn check_with_config(ra_fixture: &str, config: HighlightRelatedConfig) { + fn check_with_config( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + config: HighlightRelatedConfig, + ) { let (analysis, pos, annotations) = fixture::annotations(ra_fixture); let hls = analysis.highlight_related(config, pos).unwrap().unwrap_or_default(); diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs index 1431bd8ca29..18a3fed07ec 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs @@ -6,7 +6,9 @@ mod tests; use std::{iter, ops::Not}; use either::Either; -use hir::{db::DefDatabase, GenericSubstitution, HasCrate, HasSource, LangItem, Semantics}; +use hir::{ + db::DefDatabase, GenericDef, GenericSubstitution, HasCrate, HasSource, LangItem, Semantics, +}; use ide_db::{ defs::{Definition, IdentClass, NameRefClass, OperatorClass}, famous_defs::FamousDefs, @@ -548,24 +550,29 @@ fn goto_type_action_for_def( }); } - if let Definition::GenericParam(hir::GenericParam::TypeParam(it)) = def { - let krate = it.module(db).krate(); - let sized_trait = - db.lang_item(krate.into(), LangItem::Sized).and_then(|lang_item| lang_item.as_trait()); - - it.trait_bounds(db) - .into_iter() - .filter(|&it| Some(it.into()) != sized_trait) - .for_each(|it| push_new_def(it.into())); - } else { - let ty = match def { - Definition::Local(it) => it.ty(db), - Definition::GenericParam(hir::GenericParam::ConstParam(it)) => it.ty(db), - Definition::Field(field) => field.ty(db), - Definition::Function(function) => function.ret_type(db), - _ => return HoverAction::goto_type_from_targets(db, targets, edition), - }; + if let Ok(generic_def) = GenericDef::try_from(def) { + generic_def.type_or_const_params(db).into_iter().for_each(|it| { + walk_and_push_ty(db, &it.ty(db), &mut push_new_def); + }); + } + let ty = match def { + Definition::Local(it) => Some(it.ty(db)), + Definition::Field(field) => Some(field.ty(db)), + Definition::TupleField(field) => Some(field.ty(db)), + Definition::Const(it) => Some(it.ty(db)), + Definition::Static(it) => Some(it.ty(db)), + Definition::Function(func) => { + for param in func.assoc_fn_params(db) { + walk_and_push_ty(db, param.ty(), &mut push_new_def); + } + Some(func.ret_type(db)) + } + Definition::GenericParam(hir::GenericParam::ConstParam(it)) => Some(it.ty(db)), + Definition::GenericParam(hir::GenericParam::TypeParam(it)) => Some(it.ty(db)), + _ => None, + }; + if let Some(ty) = ty { walk_and_push_ty(db, &ty, &mut push_new_def); } @@ -592,6 +599,14 @@ fn walk_and_push_ty( traits.for_each(|it| push_new_def(it.into())); } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { push_new_def(trait_.into()); + } else if let Some(tp) = t.as_type_param(db) { + let sized_trait = db + .lang_item(t.krate(db).into(), LangItem::Sized) + .and_then(|lang_item| lang_item.as_trait()); + tp.trait_bounds(db) + .into_iter() + .filter(|&it| Some(it.into()) != sized_trait) + .for_each(|it| push_new_def(it.into())); } }); } diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs index 8fbd445d962..46242b75dd0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs @@ -3,7 +3,7 @@ use std::{env, mem, ops::Not}; use either::Either; use hir::{ - db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, AssocItemContainer, CaptureKind, + db::ExpandDatabase, Adt, AsAssocItem, AsExternAssocItem, CaptureKind, DynCompatibilityViolation, HasCrate, HasSource, HirDisplay, Layout, LayoutError, MethodViolationCode, Name, Semantics, Symbol, Trait, Type, TypeInfo, VariantDef, }; @@ -376,7 +376,7 @@ pub(super) fn process_markup( Markup::from(markup) } -fn definition_owner_name(db: &RootDatabase, def: &Definition, edition: Edition) -> Option<String> { +fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) -> Option<String> { match def { Definition::Field(f) => { let parent = f.parent_def(db); @@ -390,9 +390,52 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition, edition: Edition) _ => Some(parent_name), }; } - Definition::Local(l) => l.parent(db).name(db), Definition::Variant(e) => Some(e.parent_enum(db).name(db)), - + Definition::GenericParam(generic_param) => match generic_param.parent() { + hir::GenericDef::Adt(it) => Some(it.name(db)), + hir::GenericDef::Trait(it) => Some(it.name(db)), + hir::GenericDef::TraitAlias(it) => Some(it.name(db)), + hir::GenericDef::TypeAlias(it) => Some(it.name(db)), + + hir::GenericDef::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)), + hir::GenericDef::Function(it) => { + let container = it.as_assoc_item(db).and_then(|assoc| match assoc.container(db) { + hir::AssocItemContainer::Trait(t) => Some(t.name(db)), + hir::AssocItemContainer::Impl(i) => { + i.self_ty(db).as_adt().map(|adt| adt.name(db)) + } + }); + match container { + Some(name) => { + return Some(format!( + "{}::{}", + name.display(db, edition), + it.name(db).display(db, edition) + )) + } + None => Some(it.name(db)), + } + } + hir::GenericDef::Const(it) => { + let container = it.as_assoc_item(db).and_then(|assoc| match assoc.container(db) { + hir::AssocItemContainer::Trait(t) => Some(t.name(db)), + hir::AssocItemContainer::Impl(i) => { + i.self_ty(db).as_adt().map(|adt| adt.name(db)) + } + }); + match container { + Some(name) => { + return Some(format!( + "{}::{}", + name.display(db, edition), + it.name(db)?.display(db, edition) + )) + } + None => it.name(db), + } + } + }, + Definition::DeriveHelper(derive_helper) => Some(derive_helper.derive().name(db)), d => { if let Some(assoc_item) = d.as_assoc_item(db) { match assoc_item.container(db) { @@ -436,7 +479,7 @@ pub(super) fn definition( config: &HoverConfig, edition: Edition, ) -> Markup { - let mod_path = definition_mod_path(db, &def, edition); + let mod_path = definition_path(db, &def, edition); let label = match def { Definition::Trait(trait_) => { trait_.display_limited(db, config.max_trait_assoc_items_count, edition).to_string() @@ -915,19 +958,22 @@ fn closure_ty( Some(res) } -fn definition_mod_path(db: &RootDatabase, def: &Definition, edition: Edition) -> Option<String> { - if matches!(def, Definition::GenericParam(_) | Definition::Local(_) | Definition::Label(_)) { +fn definition_path(db: &RootDatabase, &def: &Definition, edition: Edition) -> Option<String> { + if matches!( + def, + Definition::TupleField(_) + | Definition::Label(_) + | Definition::Local(_) + | Definition::BuiltinAttr(_) + | Definition::BuiltinLifetime(_) + | Definition::BuiltinType(_) + | Definition::InlineAsmRegOrRegClass(_) + | Definition::InlineAsmOperand(_) + ) { return None; } - let container: Option<Definition> = - def.as_assoc_item(db).and_then(|assoc| match assoc.container(db) { - AssocItemContainer::Trait(trait_) => Some(trait_.into()), - AssocItemContainer::Impl(impl_) => impl_.self_ty(db).as_adt().map(|adt| adt.into()), - }); - container - .unwrap_or(*def) - .module(db) - .map(|module| path(db, module, definition_owner_name(db, def, edition), edition)) + let rendered_parent = definition_owner_name(db, def, edition); + def.module(db).map(|module| path(db, module, rendered_parent, edition)) } fn markup( diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs index 2e7637e4677..014b751f95b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs @@ -23,7 +23,7 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig { max_subst_ty_len: super::SubstTyLen::Unlimited, }; -fn check_hover_no_result(ra_fixture: &str) { +fn check_hover_no_result(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( @@ -35,7 +35,7 @@ fn check_hover_no_result(ra_fixture: &str) { } #[track_caller] -fn check(ra_fixture: &str, expect: Expect) { +fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( @@ -55,7 +55,7 @@ fn check(ra_fixture: &str, expect: Expect) { #[track_caller] fn check_hover_fields_limit( fields_count: impl Into<Option<usize>>, - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { let (analysis, position) = fixture::position(ra_fixture); @@ -81,7 +81,7 @@ fn check_hover_fields_limit( #[track_caller] fn check_hover_enum_variants_limit( variants_count: impl Into<Option<usize>>, - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { let (analysis, position) = fixture::position(ra_fixture); @@ -105,7 +105,11 @@ fn check_hover_enum_variants_limit( } #[track_caller] -fn check_assoc_count(count: usize, ra_fixture: &str, expect: Expect) { +fn check_assoc_count( + count: usize, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, +) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( @@ -126,7 +130,7 @@ fn check_assoc_count(count: usize, ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual) } -fn check_hover_no_links(ra_fixture: &str, expect: Expect) { +fn check_hover_no_links(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( @@ -143,7 +147,7 @@ fn check_hover_no_links(ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual) } -fn check_hover_no_memory_layout(ra_fixture: &str, expect: Expect) { +fn check_hover_no_memory_layout(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( @@ -160,7 +164,7 @@ fn check_hover_no_memory_layout(ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual) } -fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { +fn check_hover_no_markdown(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let hover = analysis .hover( @@ -181,7 +185,7 @@ fn check_hover_no_markdown(ra_fixture: &str, expect: Expect) { expect.assert_eq(&actual) } -fn check_actions(ra_fixture: &str, expect: Expect) { +fn check_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, file_id, position) = fixture::range_or_position(ra_fixture); let mut hover = analysis .hover( @@ -206,13 +210,13 @@ fn check_actions(ra_fixture: &str, expect: Expect) { expect.assert_debug_eq(&hover.info.actions) } -fn check_hover_range(ra_fixture: &str, expect: Expect) { +fn check_hover_range(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap().unwrap(); expect.assert_eq(hover.info.markup.as_str()) } -fn check_hover_range_actions(ra_fixture: &str, expect: Expect) { +fn check_hover_range_actions(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, range) = fixture::range(ra_fixture); let mut hover = analysis .hover(&HoverConfig { links_in_hover: true, ..HOVER_BASE_CONFIG }, range) @@ -234,7 +238,7 @@ fn check_hover_range_actions(ra_fixture: &str, expect: Expect) { expect.assert_debug_eq(&hover.info.actions); } -fn check_hover_range_no_results(ra_fixture: &str) { +fn check_hover_range_no_results(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, range) = fixture::range(ra_fixture); let hover = analysis.hover(&HOVER_BASE_CONFIG, range).unwrap(); assert!(hover.is_none()); @@ -2365,6 +2369,97 @@ fn test() { } #[test] +fn test_hover_show_type_def_for_func_param() { + check_actions( + r#" +struct Bar; +fn f(b: Bar) { + +} + +fn test() { + let b = Bar; + f$0(b); +} +"#, + expect![[r#" + [ + Reference( + FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 15, + }, + ), + GoToType( + [ + HoverGotoTypeData { + mod_path: "ra_test_fixture::Bar", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..11, + focus_range: 7..10, + name: "Bar", + kind: Struct, + description: "struct Bar", + }, + }, + ], + ), + ] + "#]], + ); +} + +#[test] +fn test_hover_show_type_def_for_trait_bound() { + check_actions( + r#" +trait Bar {} +fn f<T: Bar>(b: T) { + +} + +fn test() { + f$0(); +} +"#, + expect![[r#" + [ + Reference( + FilePositionWrapper { + file_id: FileId( + 0, + ), + offset: 16, + }, + ), + GoToType( + [ + HoverGotoTypeData { + mod_path: "ra_test_fixture::Bar", + nav: NavigationTarget { + file_id: FileId( + 0, + ), + full_range: 0..12, + focus_range: 6..9, + name: "Bar", + kind: Trait, + description: "trait Bar", + }, + }, + ], + ), + ] + "#]], + ); +} + +#[test] fn test_hover_non_ascii_space_doc() { check( " @@ -4700,6 +4795,10 @@ fn hover_lifetime() { *'lifetime* ```rust + ra_test_fixture::foo + ``` + + ```rust 'lifetime ``` "#]], @@ -4730,6 +4829,10 @@ impl<T: TraitA + TraitB> Foo<T$0> where T: Sized {} *T* ```rust + ra_test_fixture::Foo + ``` + + ```rust T: TraitA + TraitB ``` "#]], @@ -4744,6 +4847,10 @@ impl<T> Foo<T$0> {} *T* ```rust + ra_test_fixture::Foo + ``` + + ```rust T ``` "#]], @@ -4758,6 +4865,10 @@ impl<T: 'static> Foo<T$0> {} *T* ```rust + ra_test_fixture::Foo + ``` + + ```rust T: 'static ``` "#]], @@ -4778,6 +4889,10 @@ impl<T$0: Trait> Foo<T> {} *T* ```rust + ra_test_fixture::Foo + ``` + + ```rust T: Trait ``` "#]], @@ -4793,6 +4908,10 @@ impl<T$0: Trait + ?Sized> Foo<T> {} *T* ```rust + ra_test_fixture::Foo + ``` + + ```rust T: Trait + ?Sized ``` "#]], @@ -4813,6 +4932,10 @@ fn foo<T$0>() {} *T* ```rust + ra_test_fixture::foo + ``` + + ```rust T ``` @@ -4834,6 +4957,10 @@ fn foo<T$0: Sized>() {} *T* ```rust + ra_test_fixture::foo + ``` + + ```rust T ``` @@ -4855,6 +4982,10 @@ fn foo<T$0: ?Sized>() {} *T* ```rust + ra_test_fixture::foo + ``` + + ```rust T: ?Sized ``` @@ -4877,6 +5008,10 @@ fn foo<T$0: Trait>() {} *T* ```rust + ra_test_fixture::foo + ``` + + ```rust T: Trait ``` @@ -4899,6 +5034,10 @@ fn foo<T$0: Trait + Sized>() {} *T* ```rust + ra_test_fixture::foo + ``` + + ```rust T: Trait ``` @@ -4921,6 +5060,10 @@ fn foo<T$0: Trait + ?Sized>() {} *T* ```rust + ra_test_fixture::foo + ``` + + ```rust T: Trait + ?Sized ``` @@ -4942,6 +5085,10 @@ fn foo<T$0: ?Sized + Sized + Sized>() {} *T* ```rust + ra_test_fixture::foo + ``` + + ```rust T ``` @@ -4964,6 +5111,10 @@ fn foo<T$0: Sized + ?Sized + Sized + Trait>() {} *T* ```rust + ra_test_fixture::foo + ``` + + ```rust T: Trait ``` @@ -5011,6 +5162,10 @@ impl<const LEN: usize> Foo<LEN$0> {} *LEN* ```rust + ra_test_fixture::Foo + ``` + + ```rust const LEN: usize ``` "#]], @@ -6112,7 +6267,7 @@ use foo::bar::{self$0}; ``` ```rust - mod bar + pub mod bar ``` --- @@ -7857,7 +8012,7 @@ fn test() { *foo* ```rust - ra_test_fixture::S + ra_test_fixture::m::S ``` ```rust @@ -7886,7 +8041,7 @@ fn test() { *foo* ```rust - ra_test_fixture::S + ra_test_fixture::m::S ``` ```rust @@ -7916,7 +8071,7 @@ mod m { *foo* ```rust - ra_test_fixture::S + ra_test_fixture::m::inner::S ``` ```rust @@ -7946,7 +8101,7 @@ fn test() { *A* ```rust - ra_test_fixture::S + ra_test_fixture::m::S ``` ```rust @@ -7975,7 +8130,7 @@ fn test() { *A* ```rust - ra_test_fixture::S + ra_test_fixture::m::S ``` ```rust @@ -8005,7 +8160,7 @@ mod m { *A* ```rust - ra_test_fixture::S + ra_test_fixture::m::inner::S ``` ```rust diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs index faa65019eea..6d83a747d76 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs @@ -1,6 +1,6 @@ use std::{ fmt::{self, Write}, - mem::take, + mem::{self, take}, }; use either::Either; @@ -24,6 +24,7 @@ use crate::{navigation_target::TryToNav, FileId}; mod adjustment; mod bind_pat; mod binding_mode; +mod bounds; mod chaining; mod closing_brace; mod closure_captures; @@ -111,6 +112,9 @@ pub(crate) fn inlay_hints( } hints(event); } + if let Some(range_limit) = range_limit { + acc.retain(|hint| range_limit.contains_range(hint.range)); + } acc } @@ -264,6 +268,7 @@ fn hints( ast::Type::PathType(path) => lifetime::fn_path_hints(hints, ctx, famous_defs, config, file_id, path), _ => Some(()), }, + ast::GenericParamList(it) => bounds::hints(hints, famous_defs, config, file_id, it), _ => Some(()), } }; @@ -273,6 +278,7 @@ fn hints( pub struct InlayHintsConfig { pub render_colons: bool, pub type_hints: bool, + pub sized_bound: bool, pub discriminant_hints: DiscriminantHints, pub parameter_hints: bool, pub generic_parameter_hints: GenericParameterHints, @@ -294,6 +300,36 @@ pub struct InlayHintsConfig { pub closing_brace_hints_min_lines: Option<usize>, pub fields_to_resolve: InlayFieldsToResolve, } +impl InlayHintsConfig { + fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> Lazy<TextEdit> { + if self.fields_to_resolve.resolve_text_edits { + Lazy::Lazy + } else { + let edit = finish(); + never!(edit.is_empty(), "inlay hint produced an empty text edit"); + Lazy::Computed(edit) + } + } + + fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> Lazy<InlayTooltip> { + if self.fields_to_resolve.resolve_hint_tooltip + && self.fields_to_resolve.resolve_label_tooltip + { + Lazy::Lazy + } else { + let tooltip = finish(); + never!( + match &tooltip { + InlayTooltip::String(s) => s, + InlayTooltip::Markdown(s) => s, + } + .is_empty(), + "inlay hint produced an empty tooltip" + ); + Lazy::Computed(tooltip) + } + } +} #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct InlayFieldsToResolve { @@ -405,12 +441,32 @@ pub struct InlayHint { /// The actual label to show in the inlay hint. pub label: InlayHintLabel, /// Text edit to apply when "accepting" this inlay hint. - pub text_edit: Option<TextEdit>, + pub text_edit: Option<Lazy<TextEdit>>, /// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the /// hint does not support resolving. pub resolve_parent: Option<TextRange>, } +/// A type signaling that a value is either computed, or is available for computation. +#[derive(Clone, Debug)] +pub enum Lazy<T> { + Computed(T), + Lazy, +} + +impl<T> Lazy<T> { + pub fn computed(self) -> Option<T> { + match self { + Lazy::Computed(it) => Some(it), + _ => None, + } + } + + pub fn is_lazy(&self) -> bool { + matches!(self, Self::Lazy) + } +} + impl std::hash::Hash for InlayHint { fn hash<H: std::hash::Hasher>(&self, state: &mut H) { self.range.hash(state); @@ -419,7 +475,7 @@ impl std::hash::Hash for InlayHint { self.pad_right.hash(state); self.kind.hash(state); self.label.hash(state); - self.text_edit.is_some().hash(state); + mem::discriminant(&self.text_edit).hash(state); } } @@ -436,10 +492,6 @@ impl InlayHint { resolve_parent: None, } } - - pub fn needs_resolve(&self) -> Option<TextRange> { - self.resolve_parent.filter(|_| self.text_edit.is_some() || self.label.needs_resolve()) - } } #[derive(Debug, Hash)] @@ -456,7 +508,7 @@ pub struct InlayHintLabel { impl InlayHintLabel { pub fn simple( s: impl Into<String>, - tooltip: Option<InlayTooltip>, + tooltip: Option<Lazy<InlayTooltip>>, linked_location: Option<FileRange>, ) -> InlayHintLabel { InlayHintLabel { @@ -500,10 +552,6 @@ impl InlayHintLabel { } self.parts.push(part); } - - pub fn needs_resolve(&self) -> bool { - self.parts.iter().any(|part| part.linked_location.is_some() || part.tooltip.is_some()) - } } impl From<String> for InlayHintLabel { @@ -538,7 +586,6 @@ impl fmt::Debug for InlayHintLabel { } } -#[derive(Hash)] pub struct InlayHintLabelPart { pub text: String, /// Source location represented by this label part. The client will use this to fetch the part's @@ -549,13 +596,21 @@ pub struct InlayHintLabelPart { pub linked_location: Option<FileRange>, /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like /// hover requests to show. - pub tooltip: Option<InlayTooltip>, + pub tooltip: Option<Lazy<InlayTooltip>>, +} + +impl std::hash::Hash for InlayHintLabelPart { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.text.hash(state); + self.linked_location.hash(state); + self.tooltip.is_some().hash(state); + } } impl fmt::Debug for InlayHintLabelPart { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Self { text, linked_location: None, tooltip: None } => text.fmt(f), + Self { text, linked_location: None, tooltip: None | Some(Lazy::Lazy) } => text.fmt(f), Self { text, linked_location, tooltip } => f .debug_struct("InlayHintLabelPart") .field("text", text) @@ -563,7 +618,8 @@ impl fmt::Debug for InlayHintLabelPart { .field( "tooltip", &tooltip.as_ref().map_or("", |it| match it { - InlayTooltip::String(it) | InlayTooltip::Markdown(it) => it, + Lazy::Computed(InlayTooltip::String(it) | InlayTooltip::Markdown(it)) => it, + Lazy::Lazy => "", }), ) .finish(), @@ -722,19 +778,22 @@ fn hint_iterator( fn ty_to_text_edit( sema: &Semantics<'_, RootDatabase>, + config: &InlayHintsConfig, node_for_hint: &SyntaxNode, ty: &hir::Type, offset_to_insert: TextSize, - prefix: String, -) -> Option<TextEdit> { - let scope = sema.scope(node_for_hint)?; + prefix: impl Into<String>, +) -> Option<Lazy<TextEdit>> { // FIXME: Limit the length and bail out on excess somehow? - let rendered = ty.display_source_code(scope.db, scope.module().into(), false).ok()?; - - let mut builder = TextEdit::builder(); - builder.insert(offset_to_insert, prefix); - builder.insert(offset_to_insert, rendered); - Some(builder.finish()) + let rendered = sema + .scope(node_for_hint) + .and_then(|scope| ty.display_source_code(scope.db, scope.module().into(), false).ok())?; + Some(config.lazy_text_edit(|| { + let mut builder = TextEdit::builder(); + builder.insert(offset_to_insert, prefix.into()); + builder.insert(offset_to_insert, rendered); + builder.finish() + })) } fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool { @@ -760,6 +819,7 @@ mod tests { render_colons: false, type_hints: false, parameter_hints: false, + sized_bound: false, generic_parameter_hints: GenericParameterHints { type_hints: false, lifetime_hints: false, @@ -794,12 +854,15 @@ mod tests { }; #[track_caller] - pub(super) fn check(ra_fixture: &str) { + pub(super) fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_with_config(TEST_CONFIG, ra_fixture); } #[track_caller] - pub(super) fn check_with_config(config: InlayHintsConfig, ra_fixture: &str) { + pub(super) fn check_with_config( + config: InlayHintsConfig, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + ) { let (analysis, file_id) = fixture::file(ra_fixture); let mut expected = extract_annotations(&analysis.file_text(file_id).unwrap()); let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); @@ -814,16 +877,33 @@ mod tests { assert_eq!(expected, actual, "\nExpected:\n{expected:#?}\n\nActual:\n{actual:#?}"); } + #[track_caller] + pub(super) fn check_expect( + config: InlayHintsConfig, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, + ) { + let (analysis, file_id) = fixture::file(ra_fixture); + let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); + let filtered = + inlay_hints.into_iter().map(|hint| (hint.range, hint.label)).collect::<Vec<_>>(); + expect.assert_debug_eq(&filtered) + } + /// Computes inlay hints for the fixture, applies all the provided text edits and then runs /// expect test. #[track_caller] - pub(super) fn check_edit(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { + pub(super) fn check_edit( + config: InlayHintsConfig, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, + ) { let (analysis, file_id) = fixture::file(ra_fixture); let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); let edits = inlay_hints .into_iter() - .filter_map(|hint| hint.text_edit) + .filter_map(|hint| hint.text_edit?.computed()) .reduce(|mut acc, next| { acc.union(next).expect("merging text edits failed"); acc @@ -836,11 +916,15 @@ mod tests { } #[track_caller] - pub(super) fn check_no_edit(config: InlayHintsConfig, ra_fixture: &str) { + pub(super) fn check_no_edit( + config: InlayHintsConfig, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + ) { let (analysis, file_id) = fixture::file(ra_fixture); let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); - let edits: Vec<_> = inlay_hints.into_iter().filter_map(|hint| hint.text_edit).collect(); + let edits: Vec<_> = + inlay_hints.into_iter().filter_map(|hint| hint.text_edit?.computed()).collect(); assert!(edits.is_empty(), "unexpected edits: {edits:?}"); } @@ -870,4 +954,17 @@ fn foo() { "#, ); } + + #[test] + fn regression_18898() { + check( + r#" +//- proc_macros: issue_18898 +#[proc_macros::issue_18898] +fn foo() { + let +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs index 4e48baa6f14..2acd4021cc1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs @@ -162,11 +162,13 @@ pub(super) fn hints( let label = InlayHintLabelPart { text: if postfix { format!(".{}", text.trim_end()) } else { text.to_owned() }, linked_location: None, - tooltip: Some(InlayTooltip::Markdown(format!( - "`{}` → `{}` ({coercion} coercion)", - source.display(sema.db, file_id.edition()), - target.display(sema.db, file_id.edition()), - ))), + tooltip: Some(config.lazy_tooltip(|| { + InlayTooltip::Markdown(format!( + "`{}` → `{}` ({coercion} coercion)", + source.display(sema.db, file_id.edition()), + target.display(sema.db, file_id.edition()), + )) + })), }; if postfix { &mut post } else { &mut pre }.label.append_part(label); } @@ -183,7 +185,7 @@ pub(super) fn hints( return None; } if allow_edit { - let edit = { + let edit = Some(config.lazy_text_edit(|| { let mut b = TextEditBuilder::default(); if let Some(pre) = &pre { b.insert( @@ -198,14 +200,14 @@ pub(super) fn hints( ); } b.finish() - }; + })); match (&mut pre, &mut post) { (Some(pre), Some(post)) => { - pre.text_edit = Some(edit.clone()); - post.text_edit = Some(edit); + pre.text_edit = edit.clone(); + post.text_edit = edit; } - (Some(pre), None) => pre.text_edit = Some(edit), - (None, Some(post)) => post.text_edit = Some(edit), + (Some(pre), None) => pre.text_edit = edit, + (None, Some(post)) => post.text_edit = edit, (None, None) => (), } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs index 7a808fb4a92..ab5464156f0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs @@ -78,13 +78,14 @@ pub(super) fn hints( let text_edit = if let Some(colon_token) = &type_ascriptable { ty_to_text_edit( sema, + config, desc_pat.syntax(), &ty, colon_token .as_ref() .map_or_else(|| pat.syntax().text_range(), |t| t.text_range()) .end(), - if colon_token.is_some() { String::new() } else { String::from(": ") }, + if colon_token.is_some() { "" } else { ": " }, ) } else { None @@ -185,7 +186,7 @@ mod tests { }; #[track_caller] - fn check_types(ra_fixture: &str) { + fn check_types(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_with_config(InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, ra_fixture); } @@ -391,36 +392,37 @@ fn main() { #[test] fn check_hint_range_limit() { let fixture = r#" - //- minicore: fn, sized - fn foo() -> impl Fn() { loop {} } - fn foo1() -> impl Fn(f64) { loop {} } - fn foo2() -> impl Fn(f64, f64) { loop {} } - fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } - fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } - fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } - fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } - fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } - - fn main() { - let foo = foo(); - let foo = foo1(); - let foo = foo2(); - // ^^^ impl Fn(f64, f64) - let foo = foo3(); - // ^^^ impl Fn(f64, f64) -> u32 - let foo = foo4(); - let foo = foo5(); - let foo = foo6(); - let foo = foo7(); - } - "#; +//- minicore: fn, sized +fn foo() -> impl Fn() { loop {} } +fn foo1() -> impl Fn(f64) { loop {} } +fn foo2() -> impl Fn(f64, f64) { loop {} } +fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} } +fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} } +fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} } +fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} } +fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} } + +fn main() { + let foo = foo(); + let foo = foo1(); + let foo = foo2(); + // ^^^ impl Fn(f64, f64) + let foo = foo3(); + // ^^^ impl Fn(f64, f64) -> u32 + let foo = foo4(); + // ^^^ &dyn Fn(f64, f64) -> u32 + let foo = foo5(); + let foo = foo6(); + let foo = foo7(); +} +"#; let (analysis, file_id) = fixture::file(fixture); let expected = extract_annotations(&analysis.file_text(file_id).unwrap()); let inlay_hints = analysis .inlay_hints( &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG }, file_id, - Some(TextRange::new(TextSize::from(500), TextSize::from(600))), + Some(TextRange::new(TextSize::from(491), TextSize::from(640))), ) .unwrap(); let actual = @@ -1163,4 +1165,45 @@ fn main() { }"#, ); } + + #[test] + fn collapses_nested_impl_projections() { + check_types( + r#" +//- minicore: sized +trait T { + type Assoc; + fn f(self) -> Self::Assoc; +} + +trait T2 {} +trait T3<T> {} + +fn f(it: impl T<Assoc: T2>) { + let l = it.f(); + // ^ impl T2 +} + +fn f2<G: T<Assoc: T2 + 'static>>(it: G) { + let l = it.f(); + //^ impl T2 + 'static +} + +fn f3<G: T>(it: G) where <G as T>::Assoc: T2 { + let l = it.f(); + //^ impl T2 +} + +fn f4<G: T<Assoc: T2 + T3<()>>>(it: G) { + let l = it.f(); + //^ impl T2 + T3<()> +} + +fn f5<G: T<Assoc = ()>>(it: G) { + let l = it.f(); + //^ () +} +"#, + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs index 5afb98cb1c7..5bbb4fe4e66 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/binding_mode.rs @@ -99,17 +99,24 @@ pub(super) fn hints( } if let hints @ [_, ..] = &mut acc[acc_base..] { - let mut edit = TextEditBuilder::default(); - for h in &mut *hints { - edit.insert( - match h.position { - InlayHintPosition::Before => h.range.start(), - InlayHintPosition::After => h.range.end(), - }, - h.label.parts.iter().map(|p| &*p.text).collect(), - ); - } - let edit = edit.finish(); + let edit = config.lazy_text_edit(|| { + let mut edit = TextEditBuilder::default(); + for h in &mut *hints { + edit.insert( + match h.position { + InlayHintPosition::Before => h.range.start(), + InlayHintPosition::After => h.range.end(), + }, + h.label + .parts + .iter() + .map(|p| &*p.text) + .chain(h.pad_right.then_some(" ")) + .collect(), + ); + } + edit.finish() + }); hints.iter_mut().for_each(|h| h.text_edit = Some(edit.clone())); } @@ -118,8 +125,10 @@ pub(super) fn hints( #[cfg(test)] mod tests { + use expect_test::expect; + use crate::{ - inlay_hints::tests::{check_with_config, DISABLED_CONFIG}, + inlay_hints::tests::{check_edit, check_with_config, DISABLED_CONFIG}, InlayHintsConfig, }; @@ -194,4 +203,27 @@ fn foo(s @ Struct { field, .. }: &Struct) {} "#, ); } + + #[test] + fn edits() { + check_edit( + InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG }, + r#" +fn main() { + match &(0,) { + (x,) | (x,) => (), + ((x,) | (x,)) => (), + } +} +"#, + expect![[r#" + fn main() { + match &(0,) { + &(&((ref x,) | (ref x,))) => (), + &((ref x,) | (ref x,)) => (), + } + } + "#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs new file mode 100644 index 00000000000..429ddd31cbd --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs @@ -0,0 +1,152 @@ +//! Implementation of trait bound hints. +//! +//! Currently this renders the implied `Sized` bound. +use ide_db::{famous_defs::FamousDefs, FileRange}; + +use span::EditionedFileId; +use syntax::ast::{self, AstNode, HasTypeBounds}; + +use crate::{ + InlayHint, InlayHintLabel, InlayHintLabelPart, InlayHintPosition, InlayHintsConfig, InlayKind, + TryToNav, +}; + +pub(super) fn hints( + acc: &mut Vec<InlayHint>, + famous_defs @ FamousDefs(sema, _): &FamousDefs<'_, '_>, + config: &InlayHintsConfig, + _file_id: EditionedFileId, + params: ast::GenericParamList, +) -> Option<()> { + if !config.sized_bound { + return None; + } + + let linked_location = + famous_defs.core_marker_Sized().and_then(|it| it.try_to_nav(sema.db)).map(|it| { + let n = it.call_site(); + FileRange { file_id: n.file_id, range: n.focus_or_full_range() } + }); + + for param in params.type_or_const_params() { + match param { + ast::TypeOrConstParam::Type(type_param) => { + let c = type_param.colon_token().map(|it| it.text_range()); + let has_bounds = + type_param.type_bound_list().is_some_and(|it| it.bounds().next().is_some()); + acc.push(InlayHint { + range: c.unwrap_or_else(|| type_param.syntax().text_range()), + kind: InlayKind::Type, + label: { + let mut hint = InlayHintLabel::default(); + if c.is_none() { + hint.parts.push(InlayHintLabelPart { + text: ": ".to_owned(), + linked_location: None, + tooltip: None, + }); + } + hint.parts.push(InlayHintLabelPart { + text: "Sized".to_owned(), + linked_location, + tooltip: None, + }); + if has_bounds { + hint.parts.push(InlayHintLabelPart { + text: " +".to_owned(), + linked_location: None, + tooltip: None, + }); + } + hint + }, + text_edit: None, + position: InlayHintPosition::After, + pad_left: c.is_some(), + pad_right: has_bounds, + resolve_parent: Some(params.syntax().text_range()), + }); + } + ast::TypeOrConstParam::Const(_) => (), + } + } + + Some(()) +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + + use crate::inlay_hints::InlayHintsConfig; + + use crate::inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG}; + + #[track_caller] + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { + check_with_config(InlayHintsConfig { sized_bound: true, ..DISABLED_CONFIG }, ra_fixture); + } + + #[test] + fn smoke() { + check( + r#" +fn foo<T>() {} + // ^ : Sized +"#, + ); + } + + #[test] + fn with_colon() { + check( + r#" +fn foo<T:>() {} + // ^ Sized +"#, + ); + } + + #[test] + fn with_colon_and_bounds() { + check( + r#" +fn foo<T: 'static>() {} + // ^ Sized + +"#, + ); + } + + #[test] + fn location_works() { + check_expect( + InlayHintsConfig { sized_bound: true, ..DISABLED_CONFIG }, + r#" +//- minicore: sized +fn foo<T>() {} +"#, + expect![[r#" + [ + ( + 7..8, + [ + ": ", + InlayHintLabelPart { + text: "Sized", + linked_location: Some( + FileRangeWrapper { + file_id: FileId( + 1, + ), + range: 135..140, + }, + ), + tooltip: "", + }, + ], + ), + ] + "#]], + ); + } +} diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs index 028ed1650f4..7fa7ab1a94d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs @@ -81,28 +81,19 @@ mod tests { use crate::{ fixture, - inlay_hints::tests::{check_with_config, DISABLED_CONFIG, TEST_CONFIG}, + inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG}, InlayHintsConfig, }; #[track_caller] - fn check_chains(ra_fixture: &str) { + fn check_chains(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_with_config(InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG }, ra_fixture); } #[track_caller] - pub(super) fn check_expect(config: InlayHintsConfig, ra_fixture: &str, expect: Expect) { - let (analysis, file_id) = fixture::file(ra_fixture); - let inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap(); - let filtered = - inlay_hints.into_iter().map(|hint| (hint.range, hint.label)).collect::<Vec<_>>(); - expect.assert_debug_eq(&filtered) - } - - #[track_caller] pub(super) fn check_expect_clear_loc( config: InlayHintsConfig, - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect, ) { let (analysis, file_id) = fixture::file(ra_fixture); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs index 6827540fa82..7858b1d90a3 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs @@ -52,13 +52,14 @@ pub(super) fn hints( let text_edit = if has_block_body { ty_to_text_edit( sema, + config, closure.syntax(), &ty, arrow .as_ref() .map_or_else(|| param_list.syntax().text_range(), |t| t.text_range()) .end(), - if arrow.is_none() { String::from(" -> ") } else { String::new() }, + if arrow.is_none() { " -> " } else { "" }, ) } else { None diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs index 8f2949cb387..f1e1955d14c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/discriminant.rs @@ -36,13 +36,14 @@ pub(super) fn enum_hints( return None; } for variant in enum_.variant_list()?.variants() { - variant_hints(acc, sema, &enum_, &variant); + variant_hints(acc, config, sema, &enum_, &variant); } Some(()) } fn variant_hints( acc: &mut Vec<InlayHint>, + config: &InlayHintsConfig, sema: &Semantics<'_, RootDatabase>, enum_: &ast::Enum, variant: &ast::Variant, @@ -75,9 +76,11 @@ fn variant_hints( } Err(_) => format!("{eq_} ?"), }, - Some(InlayTooltip::String(match &d { - Ok(_) => "enum variant discriminant".into(), - Err(e) => format!("{e:?}"), + Some(config.lazy_tooltip(|| { + InlayTooltip::String(match &d { + Ok(_) => "enum variant discriminant".into(), + Err(e) => format!("{e:?}"), + }) })), None, ); @@ -88,7 +91,9 @@ fn variant_hints( }, kind: InlayKind::Discriminant, label, - text_edit: d.ok().map(|val| TextEdit::insert(range.start(), format!("{eq_} {val}"))), + text_edit: d.ok().map(|val| { + config.lazy_text_edit(|| TextEdit::insert(range.end(), format!("{eq_} {val}"))) + }), position: InlayHintPosition::After, pad_left: false, pad_right: false, @@ -99,13 +104,15 @@ fn variant_hints( } #[cfg(test)] mod tests { + use expect_test::expect; + use crate::inlay_hints::{ - tests::{check_with_config, DISABLED_CONFIG}, + tests::{check_edit, check_with_config, DISABLED_CONFIG}, DiscriminantHints, InlayHintsConfig, }; #[track_caller] - fn check_discriminants(ra_fixture: &str) { + fn check_discriminants(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_with_config( InlayHintsConfig { discriminant_hints: DiscriminantHints::Always, ..DISABLED_CONFIG }, ra_fixture, @@ -113,7 +120,7 @@ mod tests { } #[track_caller] - fn check_discriminants_fieldless(ra_fixture: &str) { + fn check_discriminants_fieldless(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_with_config( InlayHintsConfig { discriminant_hints: DiscriminantHints::Fieldless, @@ -207,4 +214,33 @@ enum Enum { "#, ); } + + #[test] + fn edit() { + check_edit( + InlayHintsConfig { discriminant_hints: DiscriminantHints::Always, ..DISABLED_CONFIG }, + r#" +#[repr(u8)] +enum Enum { + Variant(), + Variant1, + Variant2 {}, + Variant3, + Variant5, + Variant6, +} +"#, + expect![[r#" + #[repr(u8)] + enum Enum { + Variant() = 0, + Variant1 = 1, + Variant2 {} = 2, + Variant3 = 3, + Variant5 = 4, + Variant6 = 5, + } + "#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs index 4cc4925cda6..2bc91b68ed8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/extern_block.rs @@ -8,7 +8,7 @@ use crate::{InlayHint, InlayHintsConfig}; pub(super) fn extern_block_hints( acc: &mut Vec<InlayHint>, FamousDefs(_sema, _): &FamousDefs<'_, '_>, - _config: &InlayHintsConfig, + config: &InlayHintsConfig, _file_id: EditionedFileId, extern_block: ast::ExternBlock, ) -> Option<()> { @@ -23,7 +23,9 @@ pub(super) fn extern_block_hints( pad_right: true, kind: crate::InlayKind::ExternUnsafety, label: crate::InlayHintLabel::from("unsafe"), - text_edit: Some(TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned())), + text_edit: Some(config.lazy_text_edit(|| { + TextEdit::insert(abi.syntax().text_range().start(), "unsafe ".to_owned()) + })), resolve_parent: Some(extern_block.syntax().text_range()), }); Some(()) @@ -32,7 +34,7 @@ pub(super) fn extern_block_hints( pub(super) fn fn_hints( acc: &mut Vec<InlayHint>, FamousDefs(_sema, _): &FamousDefs<'_, '_>, - _config: &InlayHintsConfig, + config: &InlayHintsConfig, _file_id: EditionedFileId, fn_: &ast::Fn, extern_block: &ast::ExternBlock, @@ -42,14 +44,14 @@ pub(super) fn fn_hints( return None; } let fn_ = fn_.fn_token()?; - acc.push(item_hint(extern_block, fn_)); + acc.push(item_hint(config, extern_block, fn_)); Some(()) } pub(super) fn static_hints( acc: &mut Vec<InlayHint>, FamousDefs(_sema, _): &FamousDefs<'_, '_>, - _config: &InlayHintsConfig, + config: &InlayHintsConfig, _file_id: EditionedFileId, static_: &ast::Static, extern_block: &ast::ExternBlock, @@ -59,11 +61,15 @@ pub(super) fn static_hints( return None; } let static_ = static_.static_token()?; - acc.push(item_hint(extern_block, static_)); + acc.push(item_hint(config, extern_block, static_)); Some(()) } -fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint { +fn item_hint( + config: &InlayHintsConfig, + extern_block: &ast::ExternBlock, + token: SyntaxToken, +) -> InlayHint { InlayHint { range: token.text_range(), position: crate::InlayHintPosition::Before, @@ -71,7 +77,7 @@ fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint { pad_right: true, kind: crate::InlayKind::ExternUnsafety, label: crate::InlayHintLabel::from("unsafe"), - text_edit: { + text_edit: Some(config.lazy_text_edit(|| { let mut builder = TextEdit::builder(); builder.insert(token.text_range().start(), "unsafe ".to_owned()); if extern_block.unsafe_token().is_none() { @@ -79,8 +85,8 @@ fn item_hint(extern_block: &ast::ExternBlock, token: SyntaxToken) -> InlayHint { builder.insert(abi.syntax().text_range().start(), "unsafe ".to_owned()); } } - Some(builder.finish()) - }, + builder.finish() + })), resolve_parent: Some(extern_block.syntax().text_range()), } } diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs index ed7ebc3b1e7..037b328d971 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs @@ -142,7 +142,7 @@ mod tests { }; #[track_caller] - fn generic_param_name_hints_always(ra_fixture: &str) { + fn generic_param_name_hints_always(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_with_config( InlayHintsConfig { generic_parameter_hints: GenericParameterHints { @@ -157,7 +157,7 @@ mod tests { } #[track_caller] - fn generic_param_name_hints_const_only(ra_fixture: &str) { + fn generic_param_name_hints_const_only(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_with_config( InlayHintsConfig { generic_parameter_hints: GenericParameterHints { diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs index dd4b3efeecf..1358d3722f8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs @@ -108,7 +108,7 @@ pub(super) fn hints( } let mut label = InlayHintLabel::simple( name, - Some(crate::InlayTooltip::String("moz".into())), + Some(config.lazy_tooltip(|| crate::InlayTooltip::String("moz".into()))), binding_source, ); label.prepend_str("drop("); diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs index 1560df37d0d..ae5b519b43d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_static.rs @@ -39,7 +39,9 @@ pub(super) fn hints( range: t.text_range(), kind: InlayKind::Lifetime, label: "'static".into(), - text_edit: Some(TextEdit::insert(t.text_range().start(), "'static ".into())), + text_edit: Some(config.lazy_text_edit(|| { + TextEdit::insert(t.text_range().start(), "'static ".into()) + })), position: InlayHintPosition::After, pad_left: false, pad_right: true, diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs index a03ff6a52b4..a7b066700c5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs +++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs @@ -269,7 +269,7 @@ mod tests { }; #[track_caller] - fn check_params(ra_fixture: &str) { + fn check_params(#[rust_analyzer::rust_fixture] ra_fixture: &str) { check_with_config( InlayHintsConfig { parameter_hints: true, ..DISABLED_CONFIG }, ra_fixture, diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs index 5192f91a4a6..e4670177ecf 100644 --- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs +++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs @@ -307,7 +307,10 @@ mod tests { use super::*; - fn check_join_lines(ra_fixture_before: &str, ra_fixture_after: &str) { + fn check_join_lines( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, + ) { let config = JoinLinesConfig { join_else_if: true, remove_trailing_comma: true, @@ -333,7 +336,10 @@ mod tests { assert_eq_text!(ra_fixture_after, &actual); } - fn check_join_lines_sel(ra_fixture_before: &str, ra_fixture_after: &str) { + fn check_join_lines_sel( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, + ) { let config = JoinLinesConfig { join_else_if: true, remove_trailing_comma: true, diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs index 6e7c718953c..346e2862b0f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/lib.rs +++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs @@ -48,7 +48,6 @@ mod ssr; mod static_index; mod status; mod syntax_highlighting; -mod syntax_tree; mod test_explorer; mod typing; mod view_crate_graph; @@ -56,6 +55,7 @@ mod view_hir; mod view_item_tree; mod view_memory_layout; mod view_mir; +mod view_syntax_tree; use std::{iter, panic::UnwindSafe}; @@ -120,7 +120,7 @@ pub use ide_assists::{ }; pub use ide_completion::{ CallableSnippets, CompletionConfig, CompletionFieldsToResolve, CompletionItem, - CompletionItemKind, CompletionRelevance, Snippet, SnippetScope, + CompletionItemKind, CompletionItemRefMode, CompletionRelevance, Snippet, SnippetScope, }; pub use ide_db::text_edit::{Indel, TextEdit}; pub use ide_db::{ @@ -329,14 +329,8 @@ impl Analysis { }) } - /// Returns a syntax tree represented as `String`, for debug purposes. - // FIXME: use a better name here. - pub fn syntax_tree( - &self, - file_id: FileId, - text_range: Option<TextRange>, - ) -> Cancellable<String> { - self.with_db(|db| syntax_tree::syntax_tree(db, file_id, text_range)) + pub fn view_syntax_tree(&self, file_id: FileId) -> Cancellable<String> { + self.with_db(|db| view_syntax_tree::view_syntax_tree(db, file_id)) } pub fn view_hir(&self, position: FilePosition) -> Cancellable<String> { @@ -410,17 +404,11 @@ impl Analysis { &self, position: FilePosition, char_typed: char, - chars_to_exclude: Option<String>, ) -> Cancellable<Option<SourceChange>> { // Fast path to not even parse the file. if !typing::TRIGGER_CHARS.contains(char_typed) { return Ok(None); } - if let Some(chars_to_exclude) = chars_to_exclude { - if chars_to_exclude.contains(char_typed) { - return Ok(None); - } - } self.with_db(|db| typing::on_char_typed(db, position, char_typed)) } @@ -588,17 +576,17 @@ impl Analysis { self.with_db(|db| parent_module::parent_module(db, position)) } - /// Returns crates this file belongs too. + /// Returns crates that this file belongs to. pub fn crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> { self.with_db(|db| parent_module::crates_for(db, file_id)) } - /// Returns crates this file belongs too. + /// Returns crates that this file belongs to. pub fn transitive_rev_deps(&self, crate_id: CrateId) -> Cancellable<Vec<CrateId>> { self.with_db(|db| db.crate_graph().transitive_rev_deps(crate_id).collect()) } - /// Returns crates this file *might* belong too. + /// Returns crates that this file *might* belong to. pub fn relevant_crates_for(&self, file_id: FileId) -> Cancellable<Vec<CrateId>> { self.with_db(|db| db.relevant_crates(file_id).iter().copied().collect()) } diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs index 052466725fa..d97c12ebafb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs +++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs @@ -191,7 +191,7 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati MacroKind::ProcMacro => Macro, }, Definition::Field(..) | Definition::TupleField(..) => Field, - Definition::Module(..) => Module, + Definition::Module(..) | Definition::Crate(..) => Module, Definition::Function(it) => { if it.as_assoc_item(db).is_some() { if it.has_self_param(db) { @@ -405,7 +405,7 @@ mod tests { #[allow(dead_code)] #[track_caller] - fn no_moniker(ra_fixture: &str) { + fn no_moniker(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position) = fixture::position(ra_fixture); if let Some(x) = analysis.moniker(position).unwrap() { assert_eq!(x.info.len(), 0, "Moniker found but no moniker expected: {x:?}"); @@ -413,7 +413,12 @@ mod tests { } #[track_caller] - fn check_local_moniker(ra_fixture: &str, identifier: &str, package: &str, kind: MonikerKind) { + fn check_local_moniker( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + identifier: &str, + package: &str, + kind: MonikerKind, + ) { let (analysis, position) = fixture::position(ra_fixture); let x = analysis.moniker(position).unwrap().expect("no moniker found").info; assert_eq!(x.len(), 1); @@ -433,7 +438,12 @@ mod tests { } #[track_caller] - fn check_moniker(ra_fixture: &str, identifier: &str, package: &str, kind: MonikerKind) { + fn check_moniker( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + identifier: &str, + package: &str, + kind: MonikerKind, + ) { let (analysis, position) = fixture::position(ra_fixture); let x = analysis.moniker(position).unwrap().expect("no moniker found").info; assert_eq!(x.len(), 1); diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs index a232df2b82b..b0df9257ba1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs +++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs @@ -180,7 +180,11 @@ mod tests { use crate::Direction; - fn check(ra_fixture: &str, expect: Expect, direction: Direction) { + fn check( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, + direction: Direction, + ) { let (analysis, range) = fixture::range(ra_fixture); let edit = analysis.move_item(range, direction).unwrap().unwrap_or_default(); let mut file = analysis.file_text(range.file_id).unwrap().to_string(); diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs index 9259243db85..d9f80cb53dd 100644 --- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs +++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs @@ -44,13 +44,16 @@ pub struct NavigationTarget { /// /// This range must be contained within [`Self::full_range`]. pub focus_range: Option<TextRange>, + // FIXME: Symbol pub name: SmolStr, pub kind: Option<SymbolKind>, + // FIXME: Symbol pub container_name: Option<SmolStr>, pub description: Option<String>, pub docs: Option<Documentation>, /// In addition to a `name` field, a `NavigationTarget` may also be aliased /// In such cases we want a `NavigationTarget` to be accessible by its alias + // FIXME: Symbol pub alias: Option<SmolStr>, } @@ -191,11 +194,11 @@ impl TryToNav for FileSymbol { NavigationTarget { file_id, name: self.is_alias.then(|| self.def.name(db)).flatten().map_or_else( - || self.name.clone(), + || self.name.as_str().into(), |it| it.display_no_db(edition).to_smolstr(), ), - alias: self.is_alias.then(|| self.name.clone()), - kind: Some(hir::ModuleDefId::from(self.def).into()), + alias: self.is_alias.then(|| self.name.as_str().into()), + kind: Some(self.def.into()), full_range, focus_range, container_name: self.container_name.clone(), @@ -225,6 +228,7 @@ impl TryToNav for Definition { Definition::Local(it) => Some(it.to_nav(db)), Definition::Label(it) => it.try_to_nav(db), Definition::Module(it) => Some(it.to_nav(db)), + Definition::Crate(it) => Some(it.to_nav(db)), Definition::Macro(it) => it.try_to_nav(db), Definition::Field(it) => it.try_to_nav(db), Definition::SelfType(it) => it.try_to_nav(db), @@ -398,6 +402,12 @@ impl ToNav for hir::Module { } } +impl ToNav for hir::Crate { + fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> { + self.root_module().to_nav(db) + } +} + impl TryToNav for hir::Impl { fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> { let InFile { file_id, value } = self.source(db)?; diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs index b51a5cc4f4c..7a0c28d925a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs +++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs @@ -70,7 +70,7 @@ mod tests { use crate::fixture; - fn check(ra_fixture: &str) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) { let (analysis, position, expected) = fixture::annotations(ra_fixture); let navs = analysis.parent_module(position).unwrap(); let navs = navs diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs index 46714df8d69..b1079312d3b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/references.rs +++ b/src/tools/rust-analyzer/crates/ide/src/references.rs @@ -1255,11 +1255,15 @@ impl Foo { ); } - fn check(ra_fixture: &str, expect: Expect) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { check_with_scope(ra_fixture, None, expect) } - fn check_with_scope(ra_fixture: &str, search_scope: Option<SearchScope>, expect: Expect) { + fn check_with_scope( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + search_scope: Option<SearchScope>, + expect: Expect, + ) { let (analysis, pos) = fixture::position(ra_fixture); let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap(); diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs index 11bbd99110b..ba739df3092 100644 --- a/src/tools/rust-analyzer/crates/ide/src/rename.rs +++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs @@ -456,7 +456,11 @@ mod tests { use super::{RangeInfo, RenameError}; #[track_caller] - fn check(new_name: &str, ra_fixture_before: &str, ra_fixture_after: &str) { + fn check( + new_name: &str, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, + ) { let ra_fixture_after = &trim_indent(ra_fixture_after); let (analysis, position) = fixture::position(ra_fixture_before); if !ra_fixture_after.starts_with("error: ") { @@ -494,14 +498,22 @@ mod tests { }; } - fn check_expect(new_name: &str, ra_fixture: &str, expect: Expect) { + fn check_expect( + new_name: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, + ) { let (analysis, position) = fixture::position(ra_fixture); let source_change = analysis.rename(position, new_name).unwrap().expect("Expect returned a RenameError"); expect.assert_eq(&filter_expect(source_change)) } - fn check_expect_will_rename_file(new_name: &str, ra_fixture: &str, expect: Expect) { + fn check_expect_will_rename_file( + new_name: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, + ) { let (analysis, position) = fixture::position(ra_fixture); let source_change = analysis .will_rename_file(position.file_id, new_name) @@ -510,7 +522,7 @@ mod tests { expect.assert_eq(&filter_expect(source_change)) } - fn check_prepare(ra_fixture: &str, expect: Expect) { + fn check_prepare(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let result = analysis .prepare_rename(position) diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs index 3e39c750b13..32edacee51c 100644 --- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs +++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs @@ -748,7 +748,7 @@ mod tests { use crate::fixture; - fn check(ra_fixture: &str, expect: Expect) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let result = analysis .runnables(position.file_id) @@ -769,7 +769,7 @@ mod tests { expect.assert_debug_eq(&result); } - fn check_tests(ra_fixture: &str, expect: Expect) { + fn check_tests(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let (analysis, position) = fixture::position(ra_fixture); let tests = analysis.related_tests(position, None).unwrap(); let navigation_targets = tests.into_iter().map(|runnable| runnable.nav).collect::<Vec<_>>(); diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs index 84ccadc8c4e..f8c60418eb0 100644 --- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs +++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs @@ -692,7 +692,9 @@ mod tests { use crate::RootDatabase; /// Creates analysis from a multi-file fixture, returns positions marked with $0. - pub(crate) fn position(ra_fixture: &str) -> (RootDatabase, FilePosition) { + pub(crate) fn position( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + ) -> (RootDatabase, FilePosition) { let change_fixture = ChangeFixture::parse(ra_fixture); let mut database = RootDatabase::default(); database.apply_change(change_fixture.change); @@ -703,7 +705,7 @@ mod tests { } #[track_caller] - fn check(ra_fixture: &str, expect: Expect) { + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let fixture = format!( r#" //- minicore: sized, fn diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs index 6def28e0b74..77a011cac19 100644 --- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs +++ b/src/tools/rust-analyzer/crates/ide/src/ssr.rs @@ -67,7 +67,10 @@ mod tests { use super::ssr_assists; - fn get_assists(ra_fixture: &str, resolve: AssistResolveStrategy) -> Vec<Assist> { + fn get_assists( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + resolve: AssistResolveStrategy, + ) -> Vec<Assist> { let (mut db, file_id, range_or_offset) = RootDatabase::with_range_or_offset(ra_fixture); let mut local_roots = FxHashSet::default(); local_roots.insert(test_fixture::WORKSPACE); diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs index 700e166b238..8050a38b3ca 100644 --- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs +++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs @@ -138,6 +138,7 @@ impl StaticIndex<'_> { render_colons: true, discriminant_hints: crate::DiscriminantHints::Fieldless, type_hints: true, + sized_bound: false, parameter_hints: true, generic_parameter_hints: crate::GenericParameterHints { type_hints: false, @@ -290,7 +291,10 @@ mod tests { use super::VendoredLibrariesConfig; - fn check_all_ranges(ra_fixture: &str, vendored_libs_config: VendoredLibrariesConfig<'_>) { + fn check_all_ranges( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + vendored_libs_config: VendoredLibrariesConfig<'_>, + ) { let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture); let s = StaticIndex::compute(&analysis, vendored_libs_config); let mut range_set: FxHashSet<_> = ranges.iter().map(|it| it.0).collect(); @@ -309,7 +313,10 @@ mod tests { } #[track_caller] - fn check_definitions(ra_fixture: &str, vendored_libs_config: VendoredLibrariesConfig<'_>) { + fn check_definitions( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + vendored_libs_config: VendoredLibrariesConfig<'_>, + ) { let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture); let s = StaticIndex::compute(&analysis, vendored_libs_config); let mut range_set: FxHashSet<_> = ranges.iter().map(|it| it.0).collect(); diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs index 4f3d5d9d00c..22a2fe4e9eb 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs @@ -386,6 +386,9 @@ pub(super) fn highlight_def( Definition::Field(_) | Definition::TupleField(_) => { Highlight::new(HlTag::Symbol(SymbolKind::Field)) } + Definition::Crate(_) => { + Highlight::new(HlTag::Symbol(SymbolKind::Module)) | HlMod::CrateRoot + } Definition::Module(module) => { let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Module)); if module.is_crate_root() { diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs index 0a157c157c3..1be90ad6a1e 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs @@ -28,7 +28,14 @@ pub(super) fn ra_fixture( expanded: &ast::String, ) -> Option<()> { let active_parameter = ActiveParameter::at_token(sema, expanded.syntax().clone())?; - if !active_parameter.ident().is_some_and(|name| name.text().starts_with("ra_fixture")) { + let has_rust_fixture_attr = active_parameter.attrs().is_some_and(|attrs| { + attrs.filter_map(|attr| attr.as_simple_path()).any(|path| { + path.segments() + .zip(["rust_analyzer", "rust_fixture"]) + .all(|(seg, name)| seg.name_ref().map_or(false, |nr| nr.text() == name)) + }) + }); + if !has_rust_fixture_attr { return None; } let value = literal.value().ok()?; @@ -287,7 +294,9 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri fn module_def_to_hl_tag(def: Definition) -> HlTag { let symbol = match def { - Definition::Module(_) | Definition::ExternCrateDecl(_) => SymbolKind::Module, + Definition::Module(_) | Definition::Crate(_) | Definition::ExternCrateDecl(_) => { + SymbolKind::Module + } Definition::Function(_) => SymbolKind::Function, Definition::Adt(hir::Adt::Struct(_)) => SymbolKind::Struct, Definition::Adt(hir::Adt::Enum(_)) => SymbolKind::Enum, diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html index cad5a8b593f..485d44f97e1 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html @@ -46,7 +46,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> <pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span> -<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute library">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute library">skip</span><span class="attribute_bracket attribute">]</span> +<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute">skip</span><span class="attribute_bracket attribute">]</span> <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">identity</span><span class="attribute_bracket attribute">]</span> <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Default</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span> <span class="comment documentation">/// This is a doc comment</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html index edd9639768a..c6eab90e42b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_block_mod_items.html @@ -45,7 +45,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> -<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">foo</span> <span class="brace">{</span> +<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">foo</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span>foo<span class="colon">:</span>ident<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="keyword">mod</span> y <span class="brace">{</span> <span class="keyword">pub</span> <span class="keyword">struct</span> <span class="punctuation">$</span>foo<span class="semicolon">;</span> @@ -53,9 +53,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span><span class="semicolon">;</span> <span class="brace">}</span> <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> - <span class="macro">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Foo</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Foo</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="keyword">mod</span> <span class="module declaration">module</span> <span class="brace">{</span> - <span class="macro">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">foo</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="struct declaration macro public">Bar</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="keyword">fn</span> <span class="function declaration">func</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="module">y</span><span class="operator">::</span><span class="struct public">Bar</span><span class="parenthesis">)</span> <span class="brace">{</span> <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span> <span class="keyword">struct</span> <span class="struct declaration">Innerest</span><span class="angle"><</span><span class="keyword">const</span> <span class="const_param const declaration">C</span><span class="colon">:</span> <span class="unresolved_reference">usize</span><span class="angle">></span> <span class="brace">{</span> <span class="field declaration">field</span><span class="colon">:</span> <span class="bracket">[</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">{</span><span class="const_param const">C</span><span class="brace">}</span><span class="bracket">]</span> <span class="brace">}</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html index 05289cfe3fe..96cdb532dd5 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_const.html @@ -45,7 +45,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> -<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span> +<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">id</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span> <span class="brace">}</span><span class="semicolon">;</span> @@ -57,7 +57,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword const">const</span> <span class="brace">{</span> <span class="keyword">const</span> <span class="punctuation">|</span><span class="punctuation">|</span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> - <span class="macro">id</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span> + <span class="macro public">id</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span> <span class="constant const macro">CONST_ITEM</span><span class="semicolon macro">;</span> <span class="const_param const macro">CONST_PARAM</span><span class="semicolon macro">;</span> <span class="keyword const macro">const</span> <span class="brace macro">{</span> @@ -78,7 +78,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function associated const declaration static trait">assoc_const_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">unsafe_deref</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">unsafe_deref</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="brace">}</span><span class="semicolon">;</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html index aa9d23250c1..5ff96ae2a74 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html @@ -147,10 +147,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="comment documentation">/// ```</span> -<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">macro_rules</span><span class="macro_bang injected">!</span><span class="none injected"> </span><span class="macro declaration injected">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="operator injected">></span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span> -<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="macro injected">noop</span><span class="macro_bang injected">!</span><span class="parenthesis injected macro">(</span><span class="numeric_literal injected macro">1</span><span class="parenthesis injected macro">)</span><span class="semicolon injected">;</span> +<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">macro_rules</span><span class="macro_bang injected">!</span><span class="none injected"> </span><span class="macro declaration injected public">noop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="parenthesis injected">(</span><span class="punctuation injected">$</span><span class="none injected">expr</span><span class="colon injected">:</span><span class="none injected">expr</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="operator injected">=</span><span class="operator injected">></span><span class="none injected"> </span><span class="brace injected">{</span><span class="none injected"> </span><span class="punctuation injected">$</span><span class="none injected">expr </span><span class="brace injected">}</span><span class="brace injected">}</span> +<span class="comment documentation">///</span><span class="comment documentation"> </span><span class="macro injected public">noop</span><span class="macro_bang injected">!</span><span class="parenthesis injected macro">(</span><span class="numeric_literal injected macro">1</span><span class="parenthesis injected macro">)</span><span class="semicolon injected">;</span> <span class="comment documentation">/// ```</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">noop</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span>expr <span class="brace">}</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html index 7820e4e5a5f..fe5f5ab6a9a 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html @@ -45,7 +45,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> -<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root public">self</span> <span class="keyword">as</span> <span class="module crate_root declaration">this</span><span class="semicolon">;</span> +<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root">self</span> <span class="keyword">as</span> <span class="module crate_root declaration">this</span><span class="semicolon">;</span> <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">std</span><span class="semicolon">;</span> <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root declaration">abc</span><span class="semicolon">;</span> <span class="keyword">extern</span> <span class="keyword">crate</span> <span class="unresolved_reference">unresolved</span> <span class="keyword">as</span> <span class="module crate_root declaration">definitely_unresolved</span><span class="semicolon">;</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html index 6c3fbcfcf41..5fbed35192b 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html @@ -45,7 +45,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> -<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> +<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute">rust_analyzer</span><span class="operator attribute">::</span><span class="tool_module attribute">rust_fixture</span><span class="attribute_bracket attribute">]</span> <span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span><span class="none injected"> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html index 361dcd1bc37..06817af1b1f 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_issue_18089.html @@ -46,8 +46,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> <pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> - <span class="macro">template</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">template</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">template</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">template</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="brace">}</span> <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">issue_18089</span><span class="attribute_bracket attribute">]</span> -<span class="keyword">fn</span> <span class="macro declaration">template</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file +<span class="keyword">fn</span> <span class="macro declaration public">template</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html index c2bf94fd9b6..2d3407dbcda 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2015.html @@ -53,22 +53,22 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword">use</span> <span class="keyword crate_root public">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">void</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span> <span class="keyword">fn</span> <span class="function declaration">__</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="unresolved_reference">Self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// edition dependent</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">try</span> <span class="none macro">async</span> <span class="none macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">try</span> <span class="none macro">async</span> <span class="none macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// edition and context dependent</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// builtin custom syntax</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// contextual</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// reserved</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre> \ No newline at end of file +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html index a30d16d5327..f8eb5d068a8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2018.html @@ -53,22 +53,22 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword">use</span> <span class="keyword crate_root public">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">void</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span> <span class="keyword">fn</span> <span class="function declaration">__</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="unresolved_reference">Self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// edition dependent</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// edition and context dependent</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// builtin custom syntax</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// contextual</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// reserved</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre> \ No newline at end of file +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html index a30d16d5327..f8eb5d068a8 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2021.html @@ -53,22 +53,22 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword">use</span> <span class="keyword crate_root public">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">void</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span> <span class="keyword">fn</span> <span class="function declaration">__</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="unresolved_reference">Self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// edition dependent</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="none macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// edition and context dependent</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// builtin custom syntax</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// contextual</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// reserved</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre> \ No newline at end of file +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html index b82a3f9f819..fca84017069 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_keywords_2024.html @@ -53,22 +53,22 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword">use</span> <span class="keyword crate_root public">super</span><span class="operator">::</span><span class="punctuation">*</span><span class="semicolon">;</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">void</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">void</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">}</span> <span class="brace">}</span> <span class="keyword">struct</span> <span class="struct declaration">__</span> <span class="keyword">where</span> <span class="self_type_keyword">Self</span><span class="colon">:</span><span class="semicolon">;</span> <span class="keyword">fn</span> <span class="function declaration">__</span><span class="parenthesis">(</span><span class="punctuation">_</span><span class="colon">:</span> <span class="unresolved_reference">Self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">Self</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// edition dependent</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="keyword macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">try</span> <span class="keyword async macro">async</span> <span class="keyword async control macro">await</span> <span class="keyword macro">gen</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// edition and context dependent</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">dyn</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// builtin custom syntax</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">builtin</span> <span class="none macro">offset_of</span> <span class="none macro">format_args</span> <span class="none macro">asm</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// contextual</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="none macro">macro_rules</span><span class="comma macro">,</span> <span class="none macro">union</span><span class="comma macro">,</span> <span class="none macro">default</span><span class="comma macro">,</span> <span class="none macro">raw</span><span class="comma macro">,</span> <span class="none macro">auto</span><span class="comma macro">,</span> <span class="none macro">yeet</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// reserved</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> -<span class="macro">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre> \ No newline at end of file +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="keyword macro">abstract</span> <span class="keyword macro">become</span> <span class="keyword macro">box</span> <span class="keyword macro">do</span> <span class="keyword macro">final</span> <span class="keyword macro">macro</span> <span class="keyword macro">override</span> <span class="keyword macro">priv</span> <span class="keyword macro">typeof</span> <span class="keyword macro">unsized</span> <span class="keyword macro">virtual</span> <span class="keyword control macro">yield</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> +<span class="macro public">void</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span>'static 'self 'unsafe<span class="parenthesis macro">)</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html index 06673d1a73c..f640a5e6ca7 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html @@ -53,34 +53,34 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="comma macro proc_macro">,</span><span class="builtin_type macro proc_macro">i32</span> <span class="colon macro proc_macro">:</span><span class="field declaration macro proc_macro public">y</span> <span class="keyword macro proc_macro">pub</span> <span class="brace macro proc_macro">}</span> <span class="struct declaration macro proc_macro">Foo</span> <span class="keyword macro proc_macro">struct</span> <span class="brace macro proc_macro">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">def_fn</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">def_fn</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="brace">}</span> <span class="brace">}</span> -<span class="macro">def_fn</span><span class="macro_bang">!</span> <span class="brace macro">{</span> +<span class="macro public">def_fn</span><span class="macro_bang">!</span> <span class="brace macro">{</span> <span class="keyword macro">fn</span> <span class="function declaration macro">bar</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="operator macro">-</span><span class="operator macro">></span> <span class="builtin_type macro">u32</span> <span class="brace macro">{</span> <span class="numeric_literal macro">100</span> <span class="brace macro">}</span> <span class="brace macro">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">dont_color_me_braces</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">dont_color_me_braces</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="numeric_literal">0</span><span class="brace">}</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">noop</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span>expr <span class="brace">}</span> <span class="brace">}</span> <span class="comment documentation">/// textually shadow previous definition</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">noop</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">noop</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span>expr<span class="colon">:</span>expr<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span>expr <span class="brace">}</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">keyword_frag</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">keyword_frag</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="colon">:</span>ty<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>type<span class="parenthesis">)</span> <span class="brace">}</span> @@ -94,7 +94,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">id</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span> <span class="brace">}</span><span class="semicolon">;</span> @@ -106,10 +106,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> <span class="keyword">struct</span> <span class="struct declaration">TestLocal</span><span class="semicolon">;</span> <span class="comment">// regression test, TestLocal here used to not resolve</span> - <span class="keyword">let</span> <span class="punctuation">_</span><span class="colon">:</span> <span class="struct">S</span><span class="angle"><</span><span class="macro">id</span><span class="macro_bang">!</span><span class="bracket macro">[</span><span class="struct macro">TestLocal</span><span class="bracket macro">]</span><span class="angle">></span><span class="semicolon">;</span> + <span class="keyword">let</span> <span class="punctuation">_</span><span class="colon">:</span> <span class="struct">S</span><span class="angle"><</span><span class="macro public">id</span><span class="macro_bang">!</span><span class="bracket macro">[</span><span class="struct macro">TestLocal</span><span class="bracket macro">]</span><span class="angle">></span><span class="semicolon">;</span> <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">92</span><span class="comma macro">,</span><span class="parenthesis macro">)</span><span class="operator macro">.</span><span class="field library macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">dont_color_me_braces</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">noop</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro">noop</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">dont_color_me_braces</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">noop</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro macro public">noop</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="brace">}</span> </code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html index 1385ae0510a..0a7e273950d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html @@ -45,14 +45,14 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> -<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span> +<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">println</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="parenthesis">(</span><span class="brace">{</span> <span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>io<span class="colon">:</span><span class="colon">:</span>_print<span class="parenthesis">(</span>format_args_nl<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">}</span><span class="parenthesis">)</span> <span class="brace">}</span> <span class="keyword">mod</span> <span class="module declaration">panic</span> <span class="brace">{</span> - <span class="keyword">pub</span> <span class="keyword">macro</span> <span class="macro declaration">panic_2015</span> <span class="brace">{</span> + <span class="keyword">pub</span> <span class="keyword">macro</span> <span class="macro declaration public">panic_2015</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span> panic<span class="parenthesis">(</span><span class="string_literal">"explicit panic"</span><span class="parenthesis">)</span> <span class="parenthesis">)</span><span class="comma">,</span> @@ -73,12 +73,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="brace">}</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">toho</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">toho</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented"</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="parenthesis">(</span><span class="punctuation">$</span>crate<span class="colon">:</span><span class="colon">:</span>panic<span class="punctuation">!</span><span class="parenthesis">(</span><span class="string_literal">"not yet implemented: {}"</span><span class="comma">,</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="parenthesis">)</span><span class="punctuation">+</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">reuse_twice</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">reuse_twice</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="colon">:</span>literal<span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span><span class="brace">{</span>stringify<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="semicolon">;</span> format_args<span class="punctuation">!</span><span class="parenthesis">(</span><span class="punctuation">$</span>literal<span class="parenthesis">)</span><span class="brace">}</span><span class="brace">}</span><span class="semicolon">;</span> <span class="brace">}</span> @@ -95,74 +95,74 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="byte_literal">b'</span><span class="escape_sequence">\xFF</span><span class="byte_literal">'</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello, world!"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "The number is 1"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "(3, 4)"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "4"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "1 2"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">42</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "0042" with leading zerosV</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1 1 2"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "test"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="variable declaration macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="variable declaration macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "a 3 b"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "{2}"</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">27</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">-</span><span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">27</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="variable declaration macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello, world!"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "The number is 1"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "(3, 4)"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "4"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "1 2"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">42</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "0042" with leading zerosV</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1 1 2"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "test"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "2 1"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="variable declaration macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="variable declaration macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "a 3 b"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "{2}"</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier"><</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">+</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">27</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">-</span><span class="numeric_literal macro">5</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">#</span><span class="numeric_literal">0</span><span class="numeric_literal">10</span><span class="variable">x</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">27</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="variable declaration macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">></span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{}"</span> <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{{}}"</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello </span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="string_literal macro"> Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">r"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// escape sequences</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal macro">World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal macro"> World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal macro">World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal macro"> World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="invalid_escape_sequence">\xFF</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// invalid non-UTF8 escape sequences</span> <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">b"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\xFF</span><span class="invalid_escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, invalid unicodes</span> <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">c"</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\xFF</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, valid unicodes</span> <span class="keyword">let</span> <span class="variable declaration reference">backslash</span> <span class="operator">=</span> <span class="string_literal">r"\\"</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span> <span class="keyword">let</span> <span class="variable declaration">o</span><span class="colon">:</span> <span class="builtin_type">u64</span><span class="semicolon">;</span> <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">arch</span><span class="operator">::</span><span class="macro default_library library unsafe">asm</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span> @@ -175,6 +175,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword const">const</span> <span class="constant const declaration">CONSTANT</span><span class="colon">:</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="colon">:</span> <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable declaration mutable">m</span> <span class="operator">=</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="macro default_library library macro">concat</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">backslash</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">CONSTANT</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">m</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="macro default_library library macro">format_args</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="macro macro">toho</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro">reuse_twice</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">backslash</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro default_library library">format_args</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">backslash</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">CONSTANT</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">m</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="comma macro">,</span> <span class="macro default_library library macro">format_args</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="unresolved_reference macro">foo</span><span class="comma macro">,</span> <span class="string_literal macro">"bar"</span><span class="comma macro">,</span> <span class="macro macro public">toho</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="comma macro">,</span> <span class="variable macro reference">backslash</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public">reuse_twice</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">backslash</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="brace">}</span></code></pre> \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html index 4e69c82f3da..d9beac30898 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html @@ -45,12 +45,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; } .unresolved_reference { color: #FC5555; text-decoration: wavy underline; } </style> -<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span> +<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">id</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span> <span class="brace">}</span><span class="semicolon">;</span> <span class="brace">}</span> -<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">unsafe_deref</span> <span class="brace">{</span> +<span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration public">unsafe_deref</span> <span class="brace">{</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="operator">></span> <span class="brace">{</span> <span class="punctuation">*</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span> <span class="brace">}</span><span class="semicolon">;</span> @@ -92,13 +92,13 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span> <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span> - <span class="macro">id</span><span class="macro_bang">!</span> <span class="brace macro">{</span> - <span class="keyword macro unsafe">unsafe</span> <span class="brace macro">{</span> <span class="macro macro unsafe">unsafe_deref</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="brace macro">}</span> + <span class="macro public">id</span><span class="macro_bang">!</span> <span class="brace macro">{</span> + <span class="keyword macro unsafe">unsafe</span> <span class="brace macro">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="brace macro">}</span> <span class="brace macro">}</span><span class="semicolon">;</span> <span class="keyword unsafe">unsafe</span> <span class="brace">{</span> - <span class="macro unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> - <span class="macro unsafe">id</span><span class="macro_bang">!</span> <span class="brace macro">{</span> <span class="macro macro unsafe">unsafe_deref</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="brace macro">}</span><span class="semicolon">;</span> + <span class="macro public unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> + <span class="macro public unsafe">id</span><span class="macro_bang">!</span> <span class="brace macro">{</span> <span class="macro macro public unsafe">unsafe_deref</span><span class="macro_bang macro">!</span><span class="parenthesis macro">(</span><span class="parenthesis macro">)</span> <span class="brace macro">}</span><span class="semicolon">;</span> <span class="comment">// unsafe fn and method calls</span> <span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs index a20147add36..af52b33de64 100644 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs +++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs @@ -990,7 +990,7 @@ impl t for foo { fn test_injection() { check_highlighting( r##" -fn fixture(ra_fixture: &str) {} +fn fixture(#[rust_analyzer::rust_fixture] ra_fixture: &str) {} fn main() { fixture(r#" @@ -1188,7 +1188,11 @@ fn foo(x: &fn(&dyn Trait)) {} /// Highlights the code given by the `ra_fixture` argument, renders the /// result as HTML, and compares it with the HTML file given as `snapshot`. /// Note that the `snapshot` file is overwritten by the rendered HTML. -fn check_highlighting(ra_fixture: &str, expect: ExpectFile, rainbow: bool) { +fn check_highlighting( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: ExpectFile, + rainbow: bool, +) { let (analysis, file_id) = fixture::file(ra_fixture.trim()); let actual_html = &analysis.highlight_as_html(file_id, rainbow).unwrap(); expect.assert_eq(actual_html) diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs deleted file mode 100644 index e241cb82bd5..00000000000 --- a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs +++ /dev/null @@ -1,338 +0,0 @@ -use hir::Semantics; -use ide_db::{FileId, RootDatabase}; -use syntax::{ - AstNode, NodeOrToken, SourceFile, SyntaxKind::STRING, SyntaxToken, TextRange, TextSize, -}; - -// Feature: Show Syntax Tree -// -// Shows the parse tree of the current file. It exists mostly for debugging -// rust-analyzer itself. -// -// |=== -// | Editor | Action Name -// -// | VS Code | **rust-analyzer: Show Syntax Tree** -// |=== -// image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[] -pub(crate) fn syntax_tree( - db: &RootDatabase, - file_id: FileId, - text_range: Option<TextRange>, -) -> String { - let sema = Semantics::new(db); - let parse = sema.parse_guess_edition(file_id); - if let Some(text_range) = text_range { - let node = match parse.syntax().covering_element(text_range) { - NodeOrToken::Node(node) => node, - NodeOrToken::Token(token) => { - if let Some(tree) = syntax_tree_for_string(&token, text_range) { - return tree; - } - token.parent().unwrap() - } - }; - - format!("{node:#?}") - } else { - format!("{:#?}", parse.syntax()) - } -} - -/// Attempts parsing the selected contents of a string literal -/// as rust syntax and returns its syntax tree -fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> { - // When the range is inside a string - // we'll attempt parsing it as rust syntax - // to provide the syntax tree of the contents of the string - match token.kind() { - STRING => syntax_tree_for_token(token, text_range), - _ => None, - } -} - -fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> { - // Range of the full node - let node_range = node.text_range(); - let text = node.text().to_owned(); - - // We start at some point inside the node - // Either we have selected the whole string - // or our selection is inside it - let start = text_range.start() - node_range.start(); - - // how many characters we have selected - let len = text_range.len(); - - let node_len = node_range.len(); - - // We want to cap our length - let len = len.min(node_len); - - // Ensure our slice is inside the actual string - let end = - if start + len < TextSize::of(&text) { start + len } else { TextSize::of(&text) - start }; - - let text = &text[TextRange::new(start, end)]; - - // Remove possible extra string quotes from the start - // and the end of the string - let text = text - .trim_start_matches('r') - .trim_start_matches('#') - .trim_start_matches('"') - .trim_end_matches('#') - .trim_end_matches('"') - .trim() - // Remove custom markers - .replace("$0", ""); - - let parsed = SourceFile::parse(&text, span::Edition::CURRENT_FIXME); - - // If the "file" parsed without errors, - // return its syntax - if parsed.errors().is_empty() { - return Some(format!("{:#?}", parsed.tree().syntax())); - } - - None -} - -#[cfg(test)] -mod tests { - use expect_test::expect; - - use crate::fixture; - - fn check(ra_fixture: &str, expect: expect_test::Expect) { - let (analysis, file_id) = fixture::file(ra_fixture); - let syn = analysis.syntax_tree(file_id, None).unwrap(); - expect.assert_eq(&syn) - } - fn check_range(ra_fixture: &str, expect: expect_test::Expect) { - let (analysis, frange) = fixture::range(ra_fixture); - let syn = analysis.syntax_tree(frange.file_id, Some(frange.range)).unwrap(); - expect.assert_eq(&syn) - } - - #[test] - fn test_syntax_tree_without_range() { - // Basic syntax - check( - r#"fn foo() {}"#, - expect![[r#" - SOURCE_FILE@0..11 - FN@0..11 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..11 - STMT_LIST@9..11 - L_CURLY@9..10 "{" - R_CURLY@10..11 "}" - "#]], - ); - - check( - r#" -fn test() { - assert!(" - fn foo() { - } - ", ""); -}"#, - expect![[r#" - SOURCE_FILE@0..60 - FN@0..60 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..7 - IDENT@3..7 "test" - PARAM_LIST@7..9 - L_PAREN@7..8 "(" - R_PAREN@8..9 ")" - WHITESPACE@9..10 " " - BLOCK_EXPR@10..60 - STMT_LIST@10..60 - L_CURLY@10..11 "{" - WHITESPACE@11..16 "\n " - EXPR_STMT@16..58 - MACRO_EXPR@16..57 - MACRO_CALL@16..57 - PATH@16..22 - PATH_SEGMENT@16..22 - NAME_REF@16..22 - IDENT@16..22 "assert" - BANG@22..23 "!" - TOKEN_TREE@23..57 - L_PAREN@23..24 "(" - STRING@24..52 "\"\n fn foo() {\n ..." - COMMA@52..53 "," - WHITESPACE@53..54 " " - STRING@54..56 "\"\"" - R_PAREN@56..57 ")" - SEMICOLON@57..58 ";" - WHITESPACE@58..59 "\n" - R_CURLY@59..60 "}" - "#]], - ) - } - - #[test] - fn test_syntax_tree_with_range() { - check_range( - r#"$0fn foo() {}$0"#, - expect![[r#" - FN@0..11 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..11 - STMT_LIST@9..11 - L_CURLY@9..10 "{" - R_CURLY@10..11 "}" - "#]], - ); - - check_range( - r#" -fn test() { - $0assert!(" - fn foo() { - } - ", "");$0 -}"#, - expect![[r#" - EXPR_STMT@16..58 - MACRO_EXPR@16..57 - MACRO_CALL@16..57 - PATH@16..22 - PATH_SEGMENT@16..22 - NAME_REF@16..22 - IDENT@16..22 "assert" - BANG@22..23 "!" - TOKEN_TREE@23..57 - L_PAREN@23..24 "(" - STRING@24..52 "\"\n fn foo() {\n ..." - COMMA@52..53 "," - WHITESPACE@53..54 " " - STRING@54..56 "\"\"" - R_PAREN@56..57 ")" - SEMICOLON@57..58 ";" - "#]], - ); - } - - #[test] - fn test_syntax_tree_inside_string() { - check_range( - r#"fn test() { - assert!(" -$0fn foo() { -}$0 -fn bar() { -} - ", ""); -}"#, - expect![[r#" - SOURCE_FILE@0..12 - FN@0..12 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..12 - STMT_LIST@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" - "#]], - ); - - // With a raw string - check_range( - r###"fn test() { - assert!(r#" -$0fn foo() { -}$0 -fn bar() { -} - "#, ""); -}"###, - expect![[r#" - SOURCE_FILE@0..12 - FN@0..12 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..12 - STMT_LIST@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" - "#]], - ); - - // With a raw string - check_range( - r###"fn test() { - assert!(r$0#" -fn foo() { -} -fn bar() { -}"$0#, ""); -}"###, - expect![[r#" - SOURCE_FILE@0..25 - FN@0..12 - FN_KW@0..2 "fn" - WHITESPACE@2..3 " " - NAME@3..6 - IDENT@3..6 "foo" - PARAM_LIST@6..8 - L_PAREN@6..7 "(" - R_PAREN@7..8 ")" - WHITESPACE@8..9 " " - BLOCK_EXPR@9..12 - STMT_LIST@9..12 - L_CURLY@9..10 "{" - WHITESPACE@10..11 "\n" - R_CURLY@11..12 "}" - WHITESPACE@12..13 "\n" - FN@13..25 - FN_KW@13..15 "fn" - WHITESPACE@15..16 " " - NAME@16..19 - IDENT@16..19 "bar" - PARAM_LIST@19..21 - L_PAREN@19..20 "(" - R_PAREN@20..21 ")" - WHITESPACE@21..22 " " - BLOCK_EXPR@22..25 - STMT_LIST@22..25 - L_CURLY@22..23 "{" - WHITESPACE@23..24 "\n" - R_CURLY@24..25 "}" - "#]], - ); - } -} diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs index 8998934e0e8..47d75f1c957 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs @@ -436,14 +436,18 @@ mod tests { }) } - fn type_char(char_typed: char, ra_fixture_before: &str, ra_fixture_after: &str) { + fn type_char( + char_typed: char, + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, + ) { let actual = do_type_char(char_typed, ra_fixture_before) .unwrap_or_else(|| panic!("typing `{char_typed}` did nothing")); assert_eq_text!(ra_fixture_after, &actual); } - fn type_char_noop(char_typed: char, ra_fixture_before: &str) { + fn type_char_noop(char_typed: char, #[rust_analyzer::rust_fixture] ra_fixture_before: &str) { let file_change = do_type_char(char_typed, ra_fixture_before); assert_eq!(file_change, None) } @@ -889,7 +893,7 @@ fn main() { type_char_noop( '{', r##" -fn check_with(ra_fixture: &str, expect: Expect) { +fn check_with(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let base = r#" enum E { T(), R$0, C } use self::E::X; @@ -1191,7 +1195,7 @@ fn f(n: a<>b::<d>::c) {} type_char_noop( '(', r##" -fn check_with(ra_fixture: &str, expect: Expect) { +fn check_with(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) { let base = r#" enum E { T(), R$0, C } use self::E::X; diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs index 773e352220e..e249c38c73d 100644 --- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs +++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs @@ -208,7 +208,10 @@ mod tests { Some(actual) } - fn do_check(ra_fixture_before: &str, ra_fixture_after: &str) { + fn do_check( + #[rust_analyzer::rust_fixture] ra_fixture_before: &str, + #[rust_analyzer::rust_fixture] ra_fixture_after: &str, + ) { let ra_fixture_after = &trim_indent(ra_fixture_after); let actual = apply_on_enter(ra_fixture_before).unwrap(); assert_eq_text!(ra_fixture_after, &actual); diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs index 830c39e21ea..ff74e05e943 100644 --- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs +++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs @@ -220,7 +220,9 @@ mod tests { use crate::fixture; use expect_test::expect; - fn make_memory_layout(ra_fixture: &str) -> Option<RecursiveMemoryLayout> { + fn make_memory_layout( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + ) -> Option<RecursiveMemoryLayout> { let (analysis, position, _) = fixture::annotations(ra_fixture); view_memory_layout(&analysis.db, position) diff --git a/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs new file mode 100644 index 00000000000..218ee15a7dd --- /dev/null +++ b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs @@ -0,0 +1,226 @@ +use hir::Semantics; +use ide_db::{FileId, RootDatabase}; +use span::TextRange; +use stdx::format_to; +use syntax::{ + ast::{self, IsString}, + AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, WalkEvent, +}; + +// Feature: Show Syntax Tree +// +// Shows a tree view with the syntax tree of the current file +// +// |=== +// | Editor | Panel Name +// +// | VS Code | **Rust Syntax Tree** +// |=== +pub(crate) fn view_syntax_tree(db: &RootDatabase, file_id: FileId) -> String { + let sema = Semantics::new(db); + let parse = sema.parse_guess_edition(file_id); + syntax_node_to_json(parse.syntax(), None) +} + +fn syntax_node_to_json(node: &SyntaxNode, ctx: Option<InStringCtx>) -> String { + let mut result = String::new(); + for event in node.preorder_with_tokens() { + match event { + WalkEvent::Enter(it) => { + let kind = it.kind(); + let (text_range, inner_range_str) = match &ctx { + Some(ctx) => { + let inner_start: u32 = it.text_range().start().into(); + let inner_end: u32 = it.text_range().end().into(); + + let mut true_start = inner_start + ctx.offset; + let mut true_end = inner_end + ctx.offset; + for pos in &ctx.marker_positions { + if *pos >= inner_end { + break; + } + + // We conditionally add to true_start in case + // the marker is between the start and end. + true_start += 2 * (*pos < inner_start) as u32; + true_end += 2; + } + + let true_range = TextRange::new(true_start.into(), true_end.into()); + + ( + true_range, + format!( + r#","istart":{:?},"iend":{:?}"#, + it.text_range().start(), + it.text_range().end() + ), + ) + } + None => (it.text_range(), "".to_owned()), + }; + let start = text_range.start(); + let end = text_range.end(); + + match it { + NodeOrToken::Node(_) => { + format_to!( + result, + r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":["# + ); + } + NodeOrToken::Token(token) => { + let comma = if token.next_sibling_or_token().is_some() { "," } else { "" }; + match parse_rust_string(token) { + Some(parsed) => { + format_to!( + result, + r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":[{parsed}]}}{comma}"# + ); + } + None => format_to!( + result, + r#"{{"type":"Token","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str}}}{comma}"# + ), + } + } + } + } + WalkEvent::Leave(it) => match it { + NodeOrToken::Node(node) => { + let comma = if node.next_sibling_or_token().is_some() { "," } else { "" }; + format_to!(result, "]}}{comma}") + } + NodeOrToken::Token(_) => (), + }, + } + } + + result +} + +fn parse_rust_string(token: SyntaxToken) -> Option<String> { + let string_node = ast::String::cast(token)?; + let text = string_node.value().ok()?; + + let mut trim_result = String::new(); + let mut marker_positions = Vec::new(); + let mut skipped = 0; + let mut last_end = 0; + for (start, part) in text.match_indices("$0") { + marker_positions.push((start - skipped) as u32); + trim_result.push_str(&text[last_end..start]); + skipped += part.len(); + last_end = start + part.len(); + } + trim_result.push_str(&text[last_end..text.len()]); + + let parsed = SourceFile::parse(&trim_result, span::Edition::CURRENT); + + if !parsed.errors().is_empty() { + return None; + } + + let node: &SyntaxNode = &parsed.syntax_node(); + + if node.children().count() == 0 { + // C'mon, you should have at least one node other than SOURCE_FILE + return None; + } + + Some(syntax_node_to_json( + node, + Some(InStringCtx { + offset: string_node.text_range_between_quotes()?.start().into(), + marker_positions, + }), + )) +} + +struct InStringCtx { + offset: u32, + marker_positions: Vec<u32>, +} + +#[cfg(test)] +mod tests { + use expect_test::expect; + + use crate::fixture; + + fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: expect_test::Expect) { + let (analysis, file_id) = fixture::file(ra_fixture); + let syn = analysis.view_syntax_tree(file_id).unwrap(); + expect.assert_eq(&syn) + } + + #[test] + fn view_syntax_tree() { + // Basic syntax + check( + r#"fn foo() {}"#, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":11,"children":[{"type":"Node","kind":"FN","start":0,"end":11,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":6,"children":[{"type":"Token","kind":"IDENT","start":3,"end":6}]},{"type":"Node","kind":"PARAM_LIST","start":6,"end":8,"children":[{"type":"Token","kind":"L_PAREN","start":6,"end":7},{"type":"Token","kind":"R_PAREN","start":7,"end":8}]},{"type":"Token","kind":"WHITESPACE","start":8,"end":9},{"type":"Node","kind":"BLOCK_EXPR","start":9,"end":11,"children":[{"type":"Node","kind":"STMT_LIST","start":9,"end":11,"children":[{"type":"Token","kind":"L_CURLY","start":9,"end":10},{"type":"Token","kind":"R_CURLY","start":10,"end":11}]}]}]}]}"# + ]], + ); + + check( + r#" +fn test() { + assert!(" + fn foo() { + } + ", ""); +}"#, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":60,"children":[{"type":"Node","kind":"FN","start":0,"end":60,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":60,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":60,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":58,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":57,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":57,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":57,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":52,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":51,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":30,"istart":0,"iend":5},{"type":"Node","kind":"FN","start":30,"end":46,"istart":5,"iend":21,"children":[{"type":"Token","kind":"FN_KW","start":30,"end":32,"istart":5,"iend":7},{"type":"Token","kind":"WHITESPACE","start":32,"end":33,"istart":7,"iend":8},{"type":"Node","kind":"NAME","start":33,"end":36,"istart":8,"iend":11,"children":[{"type":"Token","kind":"IDENT","start":33,"end":36,"istart":8,"iend":11}]},{"type":"Node","kind":"PARAM_LIST","start":36,"end":38,"istart":11,"iend":13,"children":[{"type":"Token","kind":"L_PAREN","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_PAREN","start":37,"end":38,"istart":12,"iend":13}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"BLOCK_EXPR","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Node","kind":"STMT_LIST","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Token","kind":"L_CURLY","start":39,"end":40,"istart":14,"iend":15},{"type":"Token","kind":"WHITESPACE","start":40,"end":45,"istart":15,"iend":20},{"type":"Token","kind":"R_CURLY","start":45,"end":46,"istart":20,"iend":21}]}]}]},{"type":"Token","kind":"WHITESPACE","start":46,"end":51,"istart":21,"iend":26}]}]},{"type":"Token","kind":"COMMA","start":52,"end":53},{"type":"Token","kind":"WHITESPACE","start":53,"end":54},{"type":"Token","kind":"STRING","start":54,"end":56},{"type":"Token","kind":"R_PAREN","start":56,"end":57}]}]}]},{"type":"Token","kind":"SEMICOLON","start":57,"end":58}]},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"R_CURLY","start":59,"end":60}]}]}]}]}"# + ]], + ) + } + + #[test] + fn view_syntax_tree_inside_string() { + check( + r#"fn test() { + assert!(" +$0fn foo() { +}$0 +fn bar() { +} + ", ""); +}"#, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":65,"children":[{"type":"Node","kind":"FN","start":0,"end":65,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":65,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":65,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":63,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":62,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":62,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":62,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":57,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":56,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":26,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":26,"end":38,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":26,"end":28,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":28,"end":29,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":29,"end":32,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":29,"end":32,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":32,"end":34,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":32,"end":33,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":33,"end":34,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":34,"end":35,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":35,"end":36,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":37,"end":38,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":39,"end":51,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":39,"end":41,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":41,"end":42,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":42,"end":45,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":42,"end":45,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":45,"end":47,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":45,"end":46,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":46,"end":47,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":47,"end":48,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":48,"end":49,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":50,"end":51,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":51,"end":56,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":57,"end":58},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"STRING","start":59,"end":61},{"type":"Token","kind":"R_PAREN","start":61,"end":62}]}]}]},{"type":"Token","kind":"SEMICOLON","start":62,"end":63}]},{"type":"Token","kind":"WHITESPACE","start":63,"end":64},{"type":"Token","kind":"R_CURLY","start":64,"end":65}]}]}]}]}"# + ]], + ); + + // With a raw string + check( + r###"fn test() { + assert!(r#" +$0fn foo() { +}$0 +fn bar() { +} + "#, ""); +}"###, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":68,"children":[{"type":"Node","kind":"FN","start":0,"end":68,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":68,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":68,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":66,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":65,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":65,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":65,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":60,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":58,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":53,"end":58,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":60,"end":61},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"STRING","start":62,"end":64},{"type":"Token","kind":"R_PAREN","start":64,"end":65}]}]}]},{"type":"Token","kind":"SEMICOLON","start":65,"end":66}]},{"type":"Token","kind":"WHITESPACE","start":66,"end":67},{"type":"Token","kind":"R_CURLY","start":67,"end":68}]}]}]}]}"# + ]], + ); + + // With a raw string + check( + r###"fn test() { + assert!(r$0#" +fn foo() { +} +fn bar() { +}"$0#, ""); +}"###, + expect![[ + r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":63,"children":[{"type":"Node","kind":"FN","start":0,"end":63,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":63,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":63,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":61,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":60,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":60,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":60,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":55,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":53,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]}]}]},{"type":"Token","kind":"COMMA","start":55,"end":56},{"type":"Token","kind":"WHITESPACE","start":56,"end":57},{"type":"Token","kind":"STRING","start":57,"end":59},{"type":"Token","kind":"R_PAREN","start":59,"end":60}]}]}]},{"type":"Token","kind":"SEMICOLON","start":60,"end":61}]},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"R_CURLY","start":62,"end":63}]}]}]}]}"# + ]], + ); + } +} diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs index 66b8900109c..b3b46421b50 100644 --- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs +++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs @@ -174,6 +174,7 @@ define_symbols! { const_param_ty, Context, Continue, + convert, copy, Copy, core_panic, @@ -239,6 +240,8 @@ define_symbols! { format_unsafe_arg, format, freeze, + From, + FromStr, from_output, from_residual, from_usize, @@ -429,6 +432,7 @@ define_symbols! { shr, simd, sized, + skip, slice_len_fn, Some, start, @@ -456,6 +460,7 @@ define_symbols! { transmute_trait, transparent, Try, + TryFrom, tuple_trait, u128, u16, diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs index 73899408652..00446b27cf2 100644 --- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs +++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs @@ -242,9 +242,6 @@ impl ProjectFolders { } } - if dirs.include.is_empty() { - continue; - } vfs::loader::Entry::Directories(dirs) }; @@ -267,7 +264,7 @@ impl ProjectFolders { }; let file_set_roots = vec![VfsPath::from(ratoml_path.to_owned())]; - let entry = vfs::loader::Entry::Files(vec![ratoml_path]); + let entry = vfs::loader::Entry::Files(vec![ratoml_path.to_owned()]); res.watch.push(res.load.len()); res.load.push(entry); diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs index 9255c5a6899..7710ea79389 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs @@ -38,7 +38,10 @@ impl<'t> Bindings<'t> { nesting_state.hit = true; b = match b { Binding::Fragment(_) => break, - Binding::Missing(_) => break, + Binding::Missing(_) => { + nesting_state.at_end = true; + break; + } Binding::Nested(bs) => bs.get(nesting_state.idx).ok_or_else(|| { nesting_state.at_end = true; binding_err!("could not find nested binding `{name}`") @@ -445,6 +448,7 @@ fn expand_repeat( let mut counter = 0; let mut err = None; + let initial_restore_point = builder.restore_point(); let mut restore_point = builder.restore_point(); loop { let ExpandResult { value: (), err: e } = @@ -462,6 +466,10 @@ fn expand_repeat( counter += 1; if counter == limit { + // FIXME: This is a bug here, we get here when we shouldn't, see https://github.com/rust-lang/rust-analyzer/issues/18910. + // If we don't restore we emit a lot of nodes which causes a stack overflow down the road. For now just ignore them, + // there is always an error here anyway. + builder.restore(initial_restore_point); err = Some(ExpandError::new(ctx.call_site, ExpandErrorKind::LimitExceeded)); break; } diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs index 6abf56d4b37..bebd29ef747 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs @@ -369,7 +369,8 @@ pub fn expect_fragment<'t>( ) -> ExpandResult<tt::TokenTreesView<'t, Span>> { use ::parser; let buffer = tt_iter.remaining(); - let parser_input = to_parser_input(edition, buffer); + // FIXME: Pass the correct edition per token. Due to the split between mbe and hir-expand it's complicated. + let parser_input = to_parser_input(buffer, &mut |_ctx| edition); let tree_traversal = entry_point.parse(&parser_input, edition); let mut cursor = buffer.cursor(); let mut error = false; diff --git a/src/tools/rust-analyzer/crates/mbe/src/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/tests.rs index e63ad113ffd..fb68d35a4c8 100644 --- a/src/tools/rust-analyzer/crates/mbe/src/tests.rs +++ b/src/tools/rust-analyzer/crates/mbe/src/tests.rs @@ -26,7 +26,7 @@ fn check_( file_id: EditionedFileId::new(FileId::from_raw(0), def_edition), ast_id: ErasedFileAstId::from_raw(0), }, - SyntaxContextId::ROOT, + SyntaxContextId::root(Edition::CURRENT), decl, ) .unwrap(); @@ -39,16 +39,20 @@ fn check_( file_id: EditionedFileId::new(FileId::from_raw(1), call_edition), ast_id: ErasedFileAstId::from_raw(0), }; - let arg_tt = - syntax_bridge::parse_to_token_tree(call_edition, call_anchor, SyntaxContextId::ROOT, arg) - .unwrap(); + let arg_tt = syntax_bridge::parse_to_token_tree( + call_edition, + call_anchor, + SyntaxContextId::root(Edition::CURRENT), + arg, + ) + .unwrap(); let res = mac.expand( &arg_tt, |_| (), Span { range: TextRange::up_to(TextSize::of(arg)), anchor: call_anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, def_edition, ); @@ -59,7 +63,12 @@ fn check_( if render_debug { format_to!(expect_res, "{:#?}\n\n", res.value.0); } - let (node, _) = syntax_bridge::token_tree_to_syntax_node(&res.value.0, parse, def_edition); + let (node, _) = syntax_bridge::token_tree_to_syntax_node( + &res.value.0, + parse, + &mut |_| def_edition, + def_edition, + ); format_to!( expect_res, "{}", @@ -106,25 +115,25 @@ fn token_mapping_smoke_test() { struct MyTraitMap2 "#, expect![[r#" - SUBTREE $$ 1:0@0..20#0 1:0@0..20#0 - IDENT struct 0:0@34..40#0 - IDENT MyTraitMap2 1:0@8..19#0 - SUBTREE {} 0:0@48..49#0 0:0@100..101#0 - IDENT map 0:0@58..61#0 - PUNCH : [alone] 0:0@61..62#0 - PUNCH : [joint] 0:0@63..64#0 - PUNCH : [alone] 0:0@64..65#0 - IDENT std 0:0@65..68#0 - PUNCH : [joint] 0:0@68..69#0 - PUNCH : [alone] 0:0@69..70#0 - IDENT collections 0:0@70..81#0 - PUNCH : [joint] 0:0@81..82#0 - PUNCH : [alone] 0:0@82..83#0 - IDENT HashSet 0:0@83..90#0 - PUNCH < [alone] 0:0@90..91#0 - SUBTREE () 0:0@91..92#0 0:0@92..93#0 - PUNCH > [joint] 0:0@93..94#0 - PUNCH , [alone] 0:0@94..95#0 + SUBTREE $$ 1:0@0..20#2 1:0@0..20#2 + IDENT struct 0:0@34..40#2 + IDENT MyTraitMap2 1:0@8..19#2 + SUBTREE {} 0:0@48..49#2 0:0@100..101#2 + IDENT map 0:0@58..61#2 + PUNCH : [alone] 0:0@61..62#2 + PUNCH : [joint] 0:0@63..64#2 + PUNCH : [alone] 0:0@64..65#2 + IDENT std 0:0@65..68#2 + PUNCH : [joint] 0:0@68..69#2 + PUNCH : [alone] 0:0@69..70#2 + IDENT collections 0:0@70..81#2 + PUNCH : [joint] 0:0@81..82#2 + PUNCH : [alone] 0:0@82..83#2 + IDENT HashSet 0:0@83..90#2 + PUNCH < [alone] 0:0@90..91#2 + SUBTREE () 0:0@91..92#2 0:0@92..93#2 + PUNCH > [joint] 0:0@93..94#2 + PUNCH , [alone] 0:0@94..95#2 struct MyTraitMap2 { map: ::std::collections::HashSet<()>, @@ -153,28 +162,28 @@ fn main() { } "#, expect![[r#" - SUBTREE $$ 1:0@0..63#0 1:0@0..63#0 - IDENT fn 1:0@1..3#0 - IDENT main 1:0@4..8#0 - SUBTREE () 1:0@8..9#0 1:0@9..10#0 - SUBTREE {} 1:0@11..12#0 1:0@61..62#0 - LITERAL Integer 1 1:0@17..18#0 - PUNCH ; [alone] 1:0@18..19#0 - LITERAL Float 1.0 1:0@24..27#0 - PUNCH ; [alone] 1:0@27..28#0 - SUBTREE () 1:0@33..34#0 1:0@39..40#0 - SUBTREE () 1:0@34..35#0 1:0@37..38#0 - LITERAL Integer 1 1:0@35..36#0 - PUNCH , [alone] 1:0@36..37#0 - PUNCH , [alone] 1:0@38..39#0 - PUNCH . [alone] 1:0@40..41#0 - LITERAL Float 0.0 1:0@41..44#0 - PUNCH ; [alone] 1:0@44..45#0 - IDENT let 1:0@50..53#0 - IDENT x 1:0@54..55#0 - PUNCH = [alone] 1:0@56..57#0 - LITERAL Integer 1 1:0@58..59#0 - PUNCH ; [alone] 1:0@59..60#0 + SUBTREE $$ 1:0@0..63#2 1:0@0..63#2 + IDENT fn 1:0@1..3#2 + IDENT main 1:0@4..8#2 + SUBTREE () 1:0@8..9#2 1:0@9..10#2 + SUBTREE {} 1:0@11..12#2 1:0@61..62#2 + LITERAL Integer 1 1:0@17..18#2 + PUNCH ; [alone] 1:0@18..19#2 + LITERAL Float 1.0 1:0@24..27#2 + PUNCH ; [alone] 1:0@27..28#2 + SUBTREE () 1:0@33..34#2 1:0@39..40#2 + SUBTREE () 1:0@34..35#2 1:0@37..38#2 + LITERAL Integer 1 1:0@35..36#2 + PUNCH , [alone] 1:0@36..37#2 + PUNCH , [alone] 1:0@38..39#2 + PUNCH . [alone] 1:0@40..41#2 + LITERAL Float 0.0 1:0@41..44#2 + PUNCH ; [alone] 1:0@44..45#2 + IDENT let 1:0@50..53#2 + IDENT x 1:0@54..55#2 + PUNCH = [alone] 1:0@56..57#2 + LITERAL Integer 1 1:0@58..59#2 + PUNCH ; [alone] 1:0@59..60#2 fn main(){ 1; @@ -200,14 +209,14 @@ fn expr_2021() { const { 1 }, "#, expect![[r#" - SUBTREE $$ 1:0@0..25#0 1:0@0..25#0 - IDENT _ 1:0@5..6#0 - PUNCH ; [joint] 0:0@36..37#0 - SUBTREE () 0:0@34..35#0 0:0@34..35#0 - IDENT const 1:0@12..17#0 - SUBTREE {} 1:0@18..19#0 1:0@22..23#0 - LITERAL Integer 1 1:0@20..21#0 - PUNCH ; [alone] 0:0@39..40#0 + SUBTREE $$ 1:0@0..25#2 1:0@0..25#2 + IDENT _ 1:0@5..6#2 + PUNCH ; [joint] 0:0@36..37#2 + SUBTREE () 0:0@34..35#2 0:0@34..35#2 + IDENT const 1:0@12..17#2 + SUBTREE {} 1:0@18..19#2 1:0@22..23#2 + LITERAL Integer 1 1:0@20..21#2 + PUNCH ; [alone] 0:0@39..40#2 _; (const { @@ -228,13 +237,13 @@ fn expr_2021() { expect![[r#" ExpandError { inner: ( - 1:0@5..6#0, + 1:0@5..6#2, NoMatchingRule, ), } - SUBTREE $$ 1:0@0..8#0 1:0@0..8#0 - PUNCH ; [alone] 0:0@39..40#0 + SUBTREE $$ 1:0@0..8#2 1:0@0..8#2 + PUNCH ; [alone] 0:0@39..40#2 ;"#]], ); @@ -252,13 +261,13 @@ fn expr_2021() { expect![[r#" ExpandError { inner: ( - 1:0@5..10#0, + 1:0@5..10#2, NoMatchingRule, ), } - SUBTREE $$ 1:0@0..18#0 1:0@0..18#0 - PUNCH ; [alone] 0:0@39..40#0 + SUBTREE $$ 1:0@0..18#2 1:0@0..18#2 + PUNCH ; [alone] 0:0@39..40#2 ;"#]], ); @@ -278,26 +287,26 @@ fn expr_2021() { break 'foo bar, "#, expect![[r#" - SUBTREE $$ 1:0@0..76#0 1:0@0..76#0 - LITERAL Integer 4 1:0@5..6#0 - PUNCH ; [joint] 0:0@41..42#0 - LITERAL Str literal 1:0@12..21#0 - PUNCH ; [joint] 0:0@41..42#0 - SUBTREE () 0:0@39..40#0 0:0@39..40#0 - IDENT funcall 1:0@27..34#0 - SUBTREE () 1:0@34..35#0 1:0@35..36#0 - PUNCH ; [joint] 0:0@41..42#0 - SUBTREE () 0:0@39..40#0 0:0@39..40#0 - IDENT future 1:0@42..48#0 - PUNCH . [alone] 1:0@48..49#0 - IDENT await 1:0@49..54#0 - PUNCH ; [joint] 0:0@41..42#0 - SUBTREE () 0:0@39..40#0 0:0@39..40#0 - IDENT break 1:0@60..65#0 - PUNCH ' [joint] 1:0@66..67#0 - IDENT foo 1:0@67..70#0 - IDENT bar 1:0@71..74#0 - PUNCH ; [alone] 0:0@44..45#0 + SUBTREE $$ 1:0@0..76#2 1:0@0..76#2 + LITERAL Integer 4 1:0@5..6#2 + PUNCH ; [joint] 0:0@41..42#2 + LITERAL Str literal 1:0@12..21#2 + PUNCH ; [joint] 0:0@41..42#2 + SUBTREE () 0:0@39..40#2 0:0@39..40#2 + IDENT funcall 1:0@27..34#2 + SUBTREE () 1:0@34..35#2 1:0@35..36#2 + PUNCH ; [joint] 0:0@41..42#2 + SUBTREE () 0:0@39..40#2 0:0@39..40#2 + IDENT future 1:0@42..48#2 + PUNCH . [alone] 1:0@48..49#2 + IDENT await 1:0@49..54#2 + PUNCH ; [joint] 0:0@41..42#2 + SUBTREE () 0:0@39..40#2 0:0@39..40#2 + IDENT break 1:0@60..65#2 + PUNCH ' [joint] 1:0@66..67#2 + IDENT foo 1:0@67..70#2 + IDENT bar 1:0@71..74#2 + PUNCH ; [alone] 0:0@44..45#2 4; "literal"; @@ -319,13 +328,13 @@ fn expr_2021() { expect![[r#" ExpandError { inner: ( - 1:0@5..6#0, + 1:0@5..6#2, NoMatchingRule, ), } - SUBTREE $$ 1:0@0..8#0 1:0@0..8#0 - PUNCH ; [alone] 0:0@44..45#0 + SUBTREE $$ 1:0@0..8#2 1:0@0..8#2 + PUNCH ; [alone] 0:0@44..45#2 ;"#]], ); diff --git a/src/tools/rust-analyzer/crates/parser/src/event.rs b/src/tools/rust-analyzer/crates/parser/src/event.rs index e38571dd3ec..b197b086f37 100644 --- a/src/tools/rust-analyzer/crates/parser/src/event.rs +++ b/src/tools/rust-analyzer/crates/parser/src/event.rs @@ -12,7 +12,7 @@ use crate::{ /// `Parser` produces a flat list of `Event`s. /// They are converted to a tree-structure in /// a separate pass, via `TreeBuilder`. -#[derive(Debug)] +#[derive(Debug, PartialEq)] pub(crate) enum Event { /// This event signifies the start of the node. /// It should be either abandoned (in which case the diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs index 3b3f11be130..389c01933c9 100644 --- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs +++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs @@ -134,10 +134,12 @@ pub(super) fn let_stmt(p: &mut Parser<'_>, with_semi: Semicolon) { // test_err let_else_right_curly_brace // fn func() { let Some(_) = {Some(1)} else { panic!("h") };} if let Some(expr) = expr_after_eq { - if BlockLike::is_blocklike(expr.kind()) { - p.error( - "right curly brace `}` before `else` in a `let...else` statement not allowed", - ) + if let Some(token) = expr.last_token(p) { + if token == T!['}'] { + p.error( + "right curly brace `}` before `else` in a `let...else` statement not allowed" + ) + } } } @@ -339,13 +341,20 @@ fn lhs(p: &mut Parser<'_>, r: Restrictions) -> Option<(CompletedMarker, BlockLik // // raw reference operator // let _ = &raw mut foo; // let _ = &raw const foo; + // let _ = &raw foo; // } T![&] => { m = p.start(); p.bump(T![&]); - if p.at_contextual_kw(T![raw]) && [T![mut], T![const]].contains(&p.nth(1)) { - p.bump_remap(T![raw]); - p.bump_any(); + if p.at_contextual_kw(T![raw]) { + if [T![mut], T![const]].contains(&p.nth(1)) { + p.bump_remap(T![raw]); + p.bump_any(); + } else if p.nth_at(1, SyntaxKind::IDENT) { + // we treat raw as keyword in this case + // &raw foo; + p.bump_remap(T![raw]); + } } else { p.eat(T![mut]); } diff --git a/src/tools/rust-analyzer/crates/parser/src/parser.rs b/src/tools/rust-analyzer/crates/parser/src/parser.rs index 75a75f601cf..2f6ba525747 100644 --- a/src/tools/rust-analyzer/crates/parser/src/parser.rs +++ b/src/tools/rust-analyzer/crates/parser/src/parser.rs @@ -318,7 +318,8 @@ impl Marker { _ => unreachable!(), } p.push_event(Event::Finish); - CompletedMarker::new(self.pos, kind) + let end_pos = p.events.len() as u32; + CompletedMarker::new(self.pos, end_pos, kind) } /// Abandons the syntax tree node. All its children @@ -336,13 +337,14 @@ impl Marker { } pub(crate) struct CompletedMarker { - pos: u32, + start_pos: u32, + end_pos: u32, kind: SyntaxKind, } impl CompletedMarker { - fn new(pos: u32, kind: SyntaxKind) -> Self { - CompletedMarker { pos, kind } + fn new(start_pos: u32, end_pos: u32, kind: SyntaxKind) -> Self { + CompletedMarker { start_pos, end_pos, kind } } /// This method allows to create a new node which starts @@ -360,10 +362,10 @@ impl CompletedMarker { /// distance to `NEWSTART` into forward_parent(=2 in this case); pub(crate) fn precede(self, p: &mut Parser<'_>) -> Marker { let new_pos = p.start(); - let idx = self.pos as usize; + let idx = self.start_pos as usize; match &mut p.events[idx] { Event::Start { forward_parent, .. } => { - *forward_parent = Some(new_pos.pos - self.pos); + *forward_parent = Some(new_pos.pos - self.start_pos); } _ => unreachable!(), } @@ -376,7 +378,7 @@ impl CompletedMarker { let idx = m.pos as usize; match &mut p.events[idx] { Event::Start { forward_parent, .. } => { - *forward_parent = Some(self.pos - m.pos); + *forward_parent = Some(self.start_pos - m.pos); } _ => unreachable!(), } @@ -386,4 +388,13 @@ impl CompletedMarker { pub(crate) fn kind(&self) -> SyntaxKind { self.kind } + + pub(crate) fn last_token(&self, p: &Parser<'_>) -> Option<SyntaxKind> { + let end_pos = self.end_pos as usize; + debug_assert_eq!(p.events[end_pos - 1], Event::Finish); + p.events[..end_pos].iter().rev().find_map(|event| match event { + Event::Token { kind, .. } => Some(*kind), + _ => None, + }) + } } diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rast new file mode 100644 index 00000000000..578dc2b0f96 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rast @@ -0,0 +1,79 @@ +SOURCE_FILE + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "X" + WHITESPACE " " + RECORD_FIELD_LIST + L_CURLY "{" + RECORD_FIELD + NAME + IDENT "a" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_CURLY "}" + WHITESPACE "\n" + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "f" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + RECORD_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "X" + WHITESPACE " " + RECORD_EXPR_FIELD_LIST + L_CURLY "{" + WHITESPACE "\n " + RECORD_EXPR_FIELD + NAME_REF + IDENT "a" + COLON ":" + WHITESPACE " " + LITERAL + INT_NUMBER "1" + WHITESPACE "\n " + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE "\n " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" +error 63: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rs new file mode 100644 index 00000000000..c0c0edc9830 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0056_let_else_right_curly_brace_struct.rs @@ -0,0 +1,8 @@ +struct X {a: i32} +fn f() { + let foo = X { + a: 1 + } else { + return; + }; +} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rast new file mode 100644 index 00000000000..8e994f22d41 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rast @@ -0,0 +1,42 @@ +SOURCE_FILE + ERROR + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + LITERAL + INT_NUMBER "1" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LITERAL + INT_NUMBER "1" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" +error 0: expected an item +error 23: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rs new file mode 100644 index 00000000000..c29ddcce1ff --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_arithmetic.rs @@ -0,0 +1,5 @@ +let foo = 1 + { + 1 +} else { + return; +}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rast new file mode 100644 index 00000000000..055b583acec --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rast @@ -0,0 +1,90 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "r" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "ok" + WHITESPACE " " + EQ "=" + WHITESPACE " " + MACRO_EXPR + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "format_args" + BANG "!" + TOKEN_TREE + L_PAREN "(" + STRING "\"\"" + R_PAREN ")" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "bad" + WHITESPACE " " + EQ "=" + WHITESPACE " " + MACRO_EXPR + MACRO_CALL + PATH + PATH_SEGMENT + NAME_REF + IDENT "format_args" + BANG "!" + WHITESPACE " " + TOKEN_TREE + L_CURLY "{" + STRING "\"\"" + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE " " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE " " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE "\n" +error 89: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rs new file mode 100644 index 00000000000..5916fa07dc2 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0057_let_else_right_curly_brace_format_args.rs @@ -0,0 +1,5 @@ +fn r() { + let ok = format_args!("") else { return; }; + + let bad = format_args! {""} else { return; }; +} diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rast new file mode 100644 index 00000000000..8c7fd8c295d --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rast @@ -0,0 +1,40 @@ +SOURCE_FILE + ERROR + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + RANGE_EXPR + LITERAL + INT_NUMBER "1" + DOT2 ".." + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LITERAL + INT_NUMBER "1" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" +error 0: expected an item +error 22: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rs new file mode 100644 index 00000000000..5417131d28e --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0058_let_else_right_curly_brace_range.rs @@ -0,0 +1,5 @@ +let foo = 1..{ + 1 +} else { + return; +}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rast new file mode 100644 index 00000000000..57925a0d192 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rast @@ -0,0 +1,55 @@ +SOURCE_FILE + ERROR + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + CLOSURE_EXPR + PARAM_LIST + PIPE "|" + PARAM + IDENT_PAT + NAME + IDENT "x" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + PIPE "|" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "x" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" +error 0: expected an item +error 28: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rs new file mode 100644 index 00000000000..89c7579b071 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0059_let_else_right_curly_brace_closure.rs @@ -0,0 +1,5 @@ +let foo = |x: i32| { + x +} else { + return; +}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rast new file mode 100644 index 00000000000..4fb70bd50e3 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rast @@ -0,0 +1,38 @@ +SOURCE_FILE + ERROR + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PREFIX_EXPR + MINUS "-" + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LITERAL + INT_NUMBER "1" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" +error 0: expected an item +error 20: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rs new file mode 100644 index 00000000000..1ba7f7d761b --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0060_let_else_right_curly_brace_unary.rs @@ -0,0 +1,5 @@ +let foo = -{ + 1 +} else { + return; +}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rast new file mode 100644 index 00000000000..e8eeeee695e --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rast @@ -0,0 +1,90 @@ +SOURCE_FILE + FN + FN_KW "fn" + WHITESPACE " " + NAME + IDENT "o" + PARAM_LIST + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Result" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + COMMA "," + WHITESPACE " " + TYPE_ARG + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + R_ANGLE ">" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + YEET_EXPR + DO_KW "do" + WHITESPACE " " + YEET_KW "yeet" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + WHITESPACE "\n " + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + WHITESPACE " " + CALL_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "Ok" + ARG_LIST + L_PAREN "(" + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n " + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" +error 67: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rs new file mode 100644 index 00000000000..188fb07d91b --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0061_let_else_right_curly_brace_do_yeet.rs @@ -0,0 +1,7 @@ +fn o() -> Result<(), ()> { + let foo = do yeet { + () + } else { + return Ok(()); + }; +} \ No newline at end of file diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rast new file mode 100644 index 00000000000..cc5e1278c3d --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rast @@ -0,0 +1,40 @@ +SOURCE_FILE + ERROR + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BECOME_EXPR + BECOME_KW "become" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + TUPLE_EXPR + L_PAREN "(" + R_PAREN ")" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" +error 0: expected an item +error 27: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rs new file mode 100644 index 00000000000..622548b8f33 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0062_let_else_right_curly_brace_become.rs @@ -0,0 +1,5 @@ +let foo = become { + () +} else { + return; +}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rast new file mode 100644 index 00000000000..ea2f4f28e2d --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rast @@ -0,0 +1,38 @@ +SOURCE_FILE + ERROR + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + REF_EXPR + AMP "&" + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LITERAL + INT_NUMBER "1" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" +error 0: expected an item +error 20: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rs new file mode 100644 index 00000000000..9a00dca3689 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0063_let_else_right_curly_brace_reference.rs @@ -0,0 +1,5 @@ +let foo = &{ + 1 +} else { + return; +}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rast new file mode 100644 index 00000000000..47396140c5c --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rast @@ -0,0 +1,45 @@ +SOURCE_FILE + ERROR + LET_KW "let" + WHITESPACE " " + IDENT_PAT + NAME + IDENT "foo" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BIN_EXPR + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "bar" + WHITESPACE " " + EQ "=" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + LITERAL + INT_NUMBER "1" + WHITESPACE "\n" + R_CURLY "}" + WHITESPACE " " + LET_ELSE + ELSE_KW "else" + WHITESPACE " " + BLOCK_EXPR + STMT_LIST + L_CURLY "{" + WHITESPACE "\n " + EXPR_STMT + RETURN_EXPR + RETURN_KW "return" + SEMICOLON ";" + WHITESPACE "\n" + R_CURLY "}" + SEMICOLON ";" + WHITESPACE "\n" +error 0: expected an item +error 25: right curly brace `}` before `else` in a `let...else` statement not allowed diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rs new file mode 100644 index 00000000000..08e677416f1 --- /dev/null +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/err/0064_let_else_right_curly_brace_assignment.rs @@ -0,0 +1,5 @@ +let foo = bar = { + 1 +} else { + return; +}; diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast index 108b0802c33..8dc916e5cc5 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rast @@ -134,6 +134,25 @@ SOURCE_FILE NAME_REF IDENT "foo" SEMICOLON ";" + WHITESPACE "\n " + LET_STMT + LET_KW "let" + WHITESPACE " " + WILDCARD_PAT + UNDERSCORE "_" + WHITESPACE " " + EQ "=" + WHITESPACE " " + REF_EXPR + AMP "&" + RAW_KW "raw" + WHITESPACE " " + PATH_EXPR + PATH + PATH_SEGMENT + NAME_REF + IDENT "foo" + SEMICOLON ";" WHITESPACE "\n" R_CURLY "}" WHITESPACE "\n" diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs index c5262f4469b..31a2485b439 100644 --- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs +++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/ref_expr.rs @@ -7,4 +7,5 @@ fn foo() { // raw reference operator let _ = &raw mut foo; let _ = &raw const foo; + let _ = &raw foo; } diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs index 6ea8db9a905..4b831e4aceb 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs @@ -159,7 +159,7 @@ type ProtocolWrite<W: Write> = for<'o, 'msg> fn(out: &'o mut W, msg: &'msg str) #[cfg(test)] mod tests { use intern::{sym, Symbol}; - use span::{ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, TextRange, TextSize}; + use span::{Edition, ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, TextRange, TextSize}; use tt::{ Delimiter, DelimiterKind, Ident, Leaf, Literal, Punct, Spacing, TopSubtree, TopSubtreeBuilder, @@ -180,12 +180,12 @@ mod tests { open: Span { range: TextRange::empty(TextSize::new(0)), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, close: Span { range: TextRange::empty(TextSize::new(19)), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, kind: DelimiterKind::Invisible, }); @@ -196,7 +196,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(0), TextSize::of("struct")), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, is_raw: tt::IdentIsRaw::No, } @@ -208,7 +208,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(5), TextSize::of("r#Foo")), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, is_raw: tt::IdentIsRaw::Yes, } @@ -219,7 +219,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(10), TextSize::of("\"Foo\"")), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, kind: tt::LitKind::Str, suffix: None, @@ -229,7 +229,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(13), TextSize::of('@')), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, spacing: Spacing::Joint, })); @@ -238,7 +238,7 @@ mod tests { Span { range: TextRange::at(TextSize::new(14), TextSize::of('{')), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, ); builder.push(Leaf::Literal(Literal { @@ -246,7 +246,7 @@ mod tests { span: Span { range: TextRange::at(TextSize::new(15), TextSize::of("0u32")), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }, kind: tt::LitKind::Integer, suffix: Some(sym::u32.clone()), @@ -254,7 +254,7 @@ mod tests { builder.close(Span { range: TextRange::at(TextSize::new(19), TextSize::of('}')), anchor, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }); builder.build() diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml index 00695c54737..191535ac55e 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml @@ -14,6 +14,7 @@ doctest = false [dependencies] object.workspace = true +libc.workspace = true libloading.workspace = true memmap2.workspace = true diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs index fe15d42b4e4..cbf7a277bfa 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs @@ -28,11 +28,16 @@ fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> { #[cfg(unix)] fn load_library(file: &Utf8Path) -> Result<Library, libloading::Error> { + // not defined by POSIX, different values on mips vs other targets + #[cfg(target_env = "gnu")] + use libc::RTLD_DEEPBIND; use libloading::os::unix::Library as UnixLibrary; - use std::os::raw::c_int; + // defined by POSIX + use libloading::os::unix::RTLD_NOW; - const RTLD_NOW: c_int = 0x00002; - const RTLD_DEEPBIND: c_int = 0x00008; + // MUSL and bionic don't have it.. + #[cfg(not(target_env = "gnu"))] + const RTLD_DEEPBIND: std::os::raw::c_int = 0x0; unsafe { UnixLibrary::open(Some(file), RTLD_NOW | RTLD_DEEPBIND).map(|lib| lib.into()) } } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs index beaebf33300..c7614849e01 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs @@ -440,7 +440,7 @@ mod tests { file_id: EditionedFileId::current_edition(FileId::from_raw(0)), ast_id: span::ErasedFileAstId::from_raw(0), }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::CURRENT), }; let s = TokenStream { token_trees: vec![ @@ -482,7 +482,7 @@ mod tests { file_id: EditionedFileId::current_edition(FileId::from_raw(0)), ast_id: span::ErasedFileAstId::from_raw(0), }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::CURRENT), }; let subtree_paren_a = vec![ tt::TokenTree::Subtree(tt::Subtree { diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs index dc6e71163b2..15de88ea656 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs @@ -12,7 +12,7 @@ fn test_derive_empty() { "DeriveEmpty", r#"struct S;"#, expect!["SUBTREE $$ 1 1"], - expect!["SUBTREE $$ 42:2@0..100#0 42:2@0..100#0"], + expect!["SUBTREE $$ 42:2@0..100#2 42:2@0..100#2"], ); } @@ -29,12 +29,12 @@ fn test_derive_error() { LITERAL Str #[derive(DeriveError)] struct S ; 1 PUNCH ; [alone] 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT compile_error 42:2@0..100#0 - PUNCH ! [alone] 42:2@0..100#0 - SUBTREE () 42:2@0..100#0 42:2@0..100#0 - LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#0 - PUNCH ; [alone] 42:2@0..100#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT compile_error 42:2@0..100#2 + PUNCH ! [alone] 42:2@0..100#2 + SUBTREE () 42:2@0..100#2 42:2@0..100#2 + LITERAL Str #[derive(DeriveError)] struct S ; 42:2@0..100#2 + PUNCH ; [alone] 42:2@0..100#2"#]], ); } @@ -53,14 +53,14 @@ fn test_fn_like_macro_noop() { PUNCH , [alone] 1 SUBTREE [] 1 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT ident 42:2@0..5#0 - PUNCH , [alone] 42:2@5..6#0 - LITERAL Integer 0 42:2@7..8#0 - PUNCH , [alone] 42:2@8..9#0 - LITERAL Integer 1 42:2@10..11#0 - PUNCH , [alone] 42:2@11..12#0 - SUBTREE [] 42:2@13..14#0 42:2@14..15#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT ident 42:2@0..5#2 + PUNCH , [alone] 42:2@5..6#2 + LITERAL Integer 0 42:2@7..8#2 + PUNCH , [alone] 42:2@8..9#2 + LITERAL Integer 1 42:2@10..11#2 + PUNCH , [alone] 42:2@11..12#2 + SUBTREE [] 42:2@13..14#2 42:2@14..15#2"#]], ); } @@ -75,10 +75,10 @@ fn test_fn_like_macro_clone_ident_subtree() { PUNCH , [alone] 1 SUBTREE [] 1 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT ident 42:2@0..5#0 - PUNCH , [alone] 42:2@5..6#0 - SUBTREE [] 42:2@7..8#0 42:2@7..8#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT ident 42:2@0..5#2 + PUNCH , [alone] 42:2@5..6#2 + SUBTREE [] 42:2@7..8#2 42:2@7..8#2"#]], ); } @@ -91,8 +91,8 @@ fn test_fn_like_macro_clone_raw_ident() { SUBTREE $$ 1 1 IDENT r#async 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT r#async 42:2@0..7#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT r#async 42:2@0..7#2"#]], ); } @@ -105,8 +105,8 @@ fn test_fn_like_fn_like_span_join() { SUBTREE $$ 1 1 IDENT r#joined 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT r#joined 42:2@0..11#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT r#joined 42:2@0..11#2"#]], ); } @@ -121,10 +121,10 @@ fn test_fn_like_fn_like_span_ops() { IDENT resolved_at_def_site 1 IDENT start_span 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT set_def_site 41:1@0..150#0 - IDENT resolved_at_def_site 42:2@13..33#0 - IDENT start_span 42:2@34..34#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT set_def_site 41:1@0..150#2 + IDENT resolved_at_def_site 42:2@13..33#2 + IDENT start_span 42:2@34..34#2"#]], ); } @@ -143,14 +143,14 @@ fn test_fn_like_mk_literals() { LITERAL Integer 123i64 1 LITERAL Integer 123 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - LITERAL ByteStr byte_string 42:2@0..100#0 - LITERAL Char c 42:2@0..100#0 - LITERAL Str string 42:2@0..100#0 - LITERAL Float 3.14f64 42:2@0..100#0 - LITERAL Float 3.14 42:2@0..100#0 - LITERAL Integer 123i64 42:2@0..100#0 - LITERAL Integer 123 42:2@0..100#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + LITERAL ByteStr byte_string 42:2@0..100#2 + LITERAL Char c 42:2@0..100#2 + LITERAL Str string 42:2@0..100#2 + LITERAL Float 3.14f64 42:2@0..100#2 + LITERAL Float 3.14 42:2@0..100#2 + LITERAL Integer 123i64 42:2@0..100#2 + LITERAL Integer 123 42:2@0..100#2"#]], ); } @@ -164,9 +164,9 @@ fn test_fn_like_mk_idents() { IDENT standard 1 IDENT r#raw 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT standard 42:2@0..100#0 - IDENT r#raw 42:2@0..100#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT standard 42:2@0..100#2 + IDENT r#raw 42:2@0..100#2"#]], ); } @@ -198,27 +198,27 @@ fn test_fn_like_macro_clone_literals() { PUNCH , [alone] 1 LITERAL CStr null 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - LITERAL Integer 1u16 42:2@0..4#0 - PUNCH , [alone] 42:2@4..5#0 - LITERAL Integer 2_u32 42:2@6..11#0 - PUNCH , [alone] 42:2@11..12#0 - PUNCH - [alone] 42:2@13..14#0 - LITERAL Integer 4i64 42:2@14..18#0 - PUNCH , [alone] 42:2@18..19#0 - LITERAL Float 3.14f32 42:2@20..27#0 - PUNCH , [alone] 42:2@27..28#0 - LITERAL Str hello bridge 42:2@29..43#0 - PUNCH , [alone] 42:2@43..44#0 - LITERAL Str suffixedsuffix 42:2@45..61#0 - PUNCH , [alone] 42:2@61..62#0 - LITERAL StrRaw(2) raw 42:2@63..73#0 - PUNCH , [alone] 42:2@73..74#0 - LITERAL Char a 42:2@75..78#0 - PUNCH , [alone] 42:2@78..79#0 - LITERAL Byte b 42:2@80..84#0 - PUNCH , [alone] 42:2@84..85#0 - LITERAL CStr null 42:2@86..93#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + LITERAL Integer 1u16 42:2@0..4#2 + PUNCH , [alone] 42:2@4..5#2 + LITERAL Integer 2_u32 42:2@6..11#2 + PUNCH , [alone] 42:2@11..12#2 + PUNCH - [alone] 42:2@13..14#2 + LITERAL Integer 4i64 42:2@14..18#2 + PUNCH , [alone] 42:2@18..19#2 + LITERAL Float 3.14f32 42:2@20..27#2 + PUNCH , [alone] 42:2@27..28#2 + LITERAL Str hello bridge 42:2@29..43#2 + PUNCH , [alone] 42:2@43..44#2 + LITERAL Str suffixedsuffix 42:2@45..61#2 + PUNCH , [alone] 42:2@61..62#2 + LITERAL StrRaw(2) raw 42:2@63..73#2 + PUNCH , [alone] 42:2@73..74#2 + LITERAL Char a 42:2@75..78#2 + PUNCH , [alone] 42:2@78..79#2 + LITERAL Byte b 42:2@80..84#2 + PUNCH , [alone] 42:2@84..85#2 + LITERAL CStr null 42:2@86..93#2"#]], ); } @@ -239,12 +239,12 @@ fn test_attr_macro() { LITERAL Str #[attr_error(some arguments)] mod m {} 1 PUNCH ; [alone] 1"#]], expect![[r#" - SUBTREE $$ 42:2@0..100#0 42:2@0..100#0 - IDENT compile_error 42:2@0..100#0 - PUNCH ! [alone] 42:2@0..100#0 - SUBTREE () 42:2@0..100#0 42:2@0..100#0 - LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#0 - PUNCH ; [alone] 42:2@0..100#0"#]], + SUBTREE $$ 42:2@0..100#2 42:2@0..100#2 + IDENT compile_error 42:2@0..100#2 + PUNCH ! [alone] 42:2@0..100#2 + SUBTREE () 42:2@0..100#2 42:2@0..100#2 + LITERAL Str #[attr_error(some arguments)] mod m {} 42:2@0..100#2 + PUNCH ; [alone] 42:2@0..100#2"#]], ); } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs index 37d51050f32..4ce4544243a 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs @@ -28,13 +28,18 @@ fn parse_string_spanned( )) } -pub fn assert_expand(macro_name: &str, ra_fixture: &str, expect: Expect, expect_s: Expect) { +pub fn assert_expand( + macro_name: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, + expect: Expect, + expect_s: Expect, +) { assert_expand_impl(macro_name, ra_fixture, None, expect, expect_s); } pub fn assert_expand_attr( macro_name: &str, - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, attr_args: &str, expect: Expect, expect_s: Expect, @@ -76,7 +81,7 @@ fn assert_expand_impl( file_id: EditionedFileId::current_edition(FileId::from_raw(41)), ast_id: ErasedFileAstId::from_raw(1), }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::CURRENT), }; let call_site = Span { range: TextRange::new(0.into(), 100.into()), @@ -84,7 +89,7 @@ fn assert_expand_impl( file_id: EditionedFileId::current_edition(FileId::from_raw(42)), ast_id: ErasedFileAstId::from_raw(2), }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(span::Edition::CURRENT), }; let mixed_site = call_site; diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml index 2e3413f339b..3179c810f69 100644 --- a/src/tools/rust-analyzer/crates/profile/Cargo.toml +++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml @@ -21,7 +21,10 @@ jemalloc-ctl = { version = "0.5.0", package = "tikv-jemalloc-ctl", optional = tr perf-event = "=0.4.7" [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.52", features = ["Win32_System_Threading", "Win32_System_ProcessStatus"] } +windows-sys = { version = "0.59", features = [ + "Win32_System_Threading", + "Win32_System_ProcessStatus", +] } [features] cpu_profiler = [] diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs index 4d906c2aeb3..e4a61134620 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs @@ -92,6 +92,8 @@ pub struct CargoConfig { pub sysroot_src: Option<AbsPathBuf>, /// rustc private crate source pub rustc_source: Option<RustLibSource>, + /// Extra includes to add to the VFS. + pub extra_includes: Vec<AbsPathBuf>, pub cfg_overrides: CfgOverrides, /// Invoke `cargo check` through the RUSTC_WRAPPER. pub wrap_rustc_in_build_scripts: bool, diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs index 681bce3a5a6..f1113831125 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs @@ -49,6 +49,7 @@ fn load_workspace_from_metadata(file: &str) -> ProjectWorkspace { rustc_cfg: Vec::new(), toolchain: None, target_layout: Err("target_data_layout not loaded".into()), + extra_includes: Vec::new(), } } @@ -63,6 +64,7 @@ fn load_rust_project(file: &str) -> (CrateGraph, ProcMacroPaths) { toolchain: None, target_layout: Err(Arc::from("test has no data layout")), cfg_overrides: Default::default(), + extra_includes: Vec::new(), }; to_crate_graph(project_workspace, &mut Default::default()) } @@ -284,6 +286,7 @@ fn smoke_test_real_sysroot_cargo() { cfg_overrides: Default::default(), toolchain: None, target_layout: Err("target_data_layout not loaded".into()), + extra_includes: Vec::new(), }; project_workspace.to_crate_graph( &mut { diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs index afcc8120794..4bf9b59e7d0 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs @@ -66,7 +66,7 @@ fn rustc_print_cfg( QueryConfig::Cargo(sysroot, cargo_toml) => { let mut cmd = sysroot.tool(Tool::Cargo, cargo_toml.parent()); cmd.envs(extra_env); - cmd.args(["rustc"]).args(RUSTC_ARGS); + cmd.args(["rustc", "-Z", "unstable-options"]).args(RUSTC_ARGS); if let Some(target) = target { cmd.args(["--target", target]); } diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs index a345c6bcce4..f98d983ac06 100644 --- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs +++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs @@ -11,9 +11,8 @@ use base_db::{ }; use cfg::{CfgAtom, CfgDiff, CfgOptions}; use intern::{sym, Symbol}; -use itertools::Itertools; use paths::{AbsPath, AbsPathBuf}; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use semver::Version; use span::{Edition, FileId}; use tracing::instrument; @@ -63,6 +62,8 @@ pub struct ProjectWorkspace { pub target_layout: TargetLayoutLoadResult, /// A set of cfg overrides for this workspace. pub cfg_overrides: CfgOverrides, + /// Additional includes to add for the VFS. + pub extra_includes: Vec<AbsPathBuf>, } #[derive(Clone)] @@ -104,7 +105,15 @@ pub enum ProjectWorkspaceKind { impl fmt::Debug for ProjectWorkspace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Make sure this isn't too verbose. - let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides } = self; + let Self { + kind, + sysroot, + rustc_cfg, + toolchain, + target_layout, + cfg_overrides, + extra_includes, + } = self; match kind { ProjectWorkspaceKind::Cargo { cargo, error: _, build_scripts, rustc, set_test } => f .debug_struct("Cargo") @@ -117,6 +126,7 @@ impl fmt::Debug for ProjectWorkspace { ) .field("n_rustc_cfg", &rustc_cfg.len()) .field("n_cfg_overrides", &cfg_overrides.len()) + .field("n_extra_includes", &extra_includes.len()) .field("toolchain", &toolchain) .field("data_layout", &target_layout) .field("set_test", set_test) @@ -130,7 +140,8 @@ impl fmt::Debug for ProjectWorkspace { .field("n_rustc_cfg", &rustc_cfg.len()) .field("toolchain", &toolchain) .field("data_layout", &target_layout) - .field("n_cfg_overrides", &cfg_overrides.len()); + .field("n_cfg_overrides", &cfg_overrides.len()) + .field("n_extra_includes", &extra_includes.len()); debug_struct.finish() } @@ -144,6 +155,7 @@ impl fmt::Debug for ProjectWorkspace { .field("toolchain", &toolchain) .field("data_layout", &target_layout) .field("n_cfg_overrides", &cfg_overrides.len()) + .field("n_extra_includes", &extra_includes.len()) .field("set_test", set_test) .finish(), } @@ -320,6 +332,7 @@ impl ProjectWorkspace { cfg_overrides, toolchain, target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), + extra_includes: config.extra_includes.clone(), }) } @@ -340,6 +353,7 @@ impl ProjectWorkspace { toolchain, target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), cfg_overrides: config.cfg_overrides.clone(), + extra_includes: config.extra_includes.clone(), } } @@ -399,6 +413,7 @@ impl ProjectWorkspace { toolchain, target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), cfg_overrides: config.cfg_overrides.clone(), + extra_includes: config.extra_includes.clone(), }) } @@ -565,13 +580,20 @@ impl ProjectWorkspace { PackageRoot { is_local: krate.is_workspace_member, - include: krate.include.iter().cloned().chain(build_file).collect(), + include: krate + .include + .iter() + .cloned() + .chain(build_file) + .chain(self.extra_includes.iter().cloned()) + .collect(), exclude: krate.exclude.clone(), } }) + .collect::<FxHashSet<_>>() + .into_iter() .chain(mk_sysroot()) - .unique() - .collect(), + .collect::<Vec<_>>(), ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts, error: _, set_test: _ } => { cargo .packages() @@ -603,6 +625,8 @@ impl ProjectWorkspace { let mut exclude = vec![pkg_root.join(".git")]; if is_local { + include.extend(self.extra_includes.iter().cloned()); + exclude.push(pkg_root.join("target")); } else { exclude.push(pkg_root.join("tests")); @@ -619,11 +643,6 @@ impl ProjectWorkspace { exclude: Vec::new(), }) })) - .chain(cargo.is_virtual_workspace().then(|| PackageRoot { - is_local: true, - include: vec![cargo.workspace_root().to_path_buf()], - exclude: Vec::new(), - })) .collect() } ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => { @@ -661,6 +680,8 @@ impl ProjectWorkspace { let mut exclude = vec![pkg_root.join(".git")]; if is_local { + include.extend(self.extra_includes.iter().cloned()); + exclude.push(pkg_root.join("target")); } else { exclude.push(pkg_root.join("tests")); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml index d06130ce8c5..c24cbb4a311 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml @@ -76,7 +76,10 @@ vfs.workspace = true paths.workspace = true [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.52", features = ["Win32_System_Diagnostics_Debug", "Win32_System_Threading"] } +windows-sys = { version = "0.59", features = [ + "Win32_System_Diagnostics_Debug", + "Win32_System_Threading", +] } [target.'cfg(not(target_env = "msvc"))'.dependencies] jemallocator = { version = "0.5.0", package = "tikv-jemallocator", optional = true } diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs index afe3455b780..bcaec520195 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs @@ -1051,6 +1051,7 @@ impl flags::AnalysisStats { &InlayHintsConfig { render_colons: false, type_hints: true, + sized_bound: false, discriminant_hints: ide::DiscriminantHints::Always, parameter_hints: true, generic_parameter_hints: ide::GenericParameterHints { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs index 6b0ce4db7c9..199f61e70f0 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs @@ -93,6 +93,7 @@ impl Tester { toolchain: None, target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())), cfg_overrides: Default::default(), + extra_includes: vec![], }; let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check: false, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs index 6ca7d9ac057..dc0f722aae6 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs @@ -518,7 +518,7 @@ mod test { use test_fixture::ChangeFixture; use vfs::VfsPath; - fn position(ra_fixture: &str) -> (AnalysisHost, FilePosition) { + fn position(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (AnalysisHost, FilePosition) { let mut host = AnalysisHost::default(); let change_fixture = ChangeFixture::parse(ra_fixture); host.raw_database_mut().apply_change(change_fixture.change); @@ -530,7 +530,7 @@ mod test { /// If expected == "", then assert that there are no symbols (this is basically local symbol) #[track_caller] - fn check_symbol(ra_fixture: &str, expected: &str) { + fn check_symbol(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: &str) { let (host, position) = position(ra_fixture); let analysis = host.analysis(); diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs index 30f0031905f..3dc4379258f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs @@ -185,6 +185,8 @@ config_data! { inlayHints_genericParameterHints_type_enable: bool = false, /// Whether to show implicit drop hints. inlayHints_implicitDrops_enable: bool = false, + /// Whether to show inlay hints for the implied type parameter `Sized` bound. + inlayHints_implicitSizedBoundHints_enable: bool = false, /// Whether to show inlay type hints for elided lifetimes in function signatures. inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = LifetimeElisionDef::Never, /// Whether to prefer using parameter names as the name for elided lifetime hints if possible. @@ -324,8 +326,16 @@ config_data! { /// Show documentation. signatureInfo_documentation_enable: bool = true, - /// Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. - typing_excludeChars: Option<String> = Some("|<".to_owned()), + /// Specify the characters allowed to invoke special on typing triggers. + /// - typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression + /// - typing `=` between two expressions adds `;` when in statement position + /// - typing `=` to turn an assignment into an equality comparison removes `;` when in expression position + /// - typing `.` in a chain method call auto-indents + /// - typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression + /// - typing `{` in a use item adds a closing `}` in the right place + /// - typing `>` to complete a return type `->` will insert a whitespace after it + /// - typing `<` in a path or type position inserts a closing `>` after the path or type. + typing_triggerChars: Option<String> = Some("=.".to_owned()), /// Enables automatic discovery of projects using [`DiscoverWorkspaceConfig::command`]. @@ -571,11 +581,8 @@ config_data! { /// avoid checking unnecessary things. cargo_buildScripts_useRustcWrapper: bool = true, /// List of cfg options to enable with the given values. - cargo_cfgs: FxHashMap<String, Option<String>> = { - let mut m = FxHashMap::default(); - m.insert("debug_assertions".to_owned(), None); - m.insert("miri".to_owned(), None); - m + cargo_cfgs: Vec<String> = { + vec!["debug_assertions".into(), "miri".into()] }, /// Extra arguments that are passed to every cargo invocation. cargo_extraArgs: Vec<String> = vec![], @@ -728,6 +735,10 @@ config_data! { /// available on a nightly build. rustfmt_rangeFormatting_enable: bool = false, + /// Additional paths to include in the VFS. Generally for code that is + /// generated or otherwise managed by a build system outside of Cargo, + /// though Cargo might be the eventual consumer. + vfs_extraIncludes: Vec<String> = vec![], /// Workspace symbol search kind. workspace_symbol_search_kind: WorkspaceSymbolSearchKindDef = WorkspaceSymbolSearchKindDef::OnlyTypes, @@ -1620,6 +1631,7 @@ impl Config { InlayHintsConfig { render_colons: self.inlayHints_renderColons().to_owned(), type_hints: self.inlayHints_typeHints_enable().to_owned(), + sized_bound: self.inlayHints_implicitSizedBoundHints_enable().to_owned(), parameter_hints: self.inlayHints_parameterHints_enable().to_owned(), generic_parameter_hints: GenericParameterHints { type_hints: self.inlayHints_genericParameterHints_type_enable().to_owned(), @@ -1926,6 +1938,13 @@ impl Config { }); let sysroot_src = self.cargo_sysrootSrc(source_root).as_ref().map(|sysroot| self.root_path.join(sysroot)); + let extra_includes = self + .vfs_extraIncludes(source_root) + .iter() + .map(String::as_str) + .map(AbsPathBuf::try_from) + .filter_map(Result::ok) + .collect(); CargoConfig { all_targets: *self.cargo_allTargets(source_root), @@ -1940,10 +1959,18 @@ impl Config { sysroot, sysroot_src, rustc_source, + extra_includes, cfg_overrides: project_model::CfgOverrides { global: CfgDiff::new( self.cargo_cfgs(source_root) .iter() + // parse any cfg setting formatted as key=value or just key (without value) + .filter_map(|s| { + let mut sp = s.splitn(2, "="); + let key = sp.next(); + let val = sp.next(); + key.map(|key| (key, val)) + }) .map(|(key, val)| match val { Some(val) => CfgAtom::KeyValue { key: Symbol::intern(key), @@ -2232,8 +2259,8 @@ impl Config { } } - pub fn typing_exclude_chars(&self) -> Option<String> { - self.typing_excludeChars().clone() + pub fn typing_trigger_chars(&self) -> &str { + self.typing_triggerChars().as_deref().unwrap_or_default() } // VSCode is our reference implementation, so we allow ourselves to work around issues by diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs index 7ac70efe2d6..190015d7faa 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs @@ -136,15 +136,13 @@ pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> anyhow::Res Ok(out) } -pub(crate) fn handle_syntax_tree( +pub(crate) fn handle_view_syntax_tree( snap: GlobalStateSnapshot, - params: lsp_ext::SyntaxTreeParams, + params: lsp_ext::ViewSyntaxTreeParams, ) -> anyhow::Result<String> { - let _p = tracing::info_span!("handle_syntax_tree").entered(); + let _p = tracing::info_span!("handle_view_syntax_tree").entered(); let id = from_proto::file_id(&snap, ¶ms.text_document.uri)?; - let line_index = snap.file_line_index(id)?; - let text_range = params.range.and_then(|r| from_proto::text_range(&line_index, r).ok()); - let res = snap.analysis.syntax_tree(id, text_range)?; + let res = snap.analysis.view_syntax_tree(id)?; Ok(res) } @@ -436,29 +434,24 @@ pub(crate) fn handle_on_type_formatting( params: lsp_types::DocumentOnTypeFormattingParams, ) -> anyhow::Result<Option<Vec<lsp_ext::SnippetTextEdit>>> { let _p = tracing::info_span!("handle_on_type_formatting").entered(); + let char_typed = params.ch.chars().next().unwrap_or('\0'); + if !snap.config.typing_trigger_chars().contains(char_typed) { + return Ok(None); + } + let mut position = from_proto::file_position(&snap, params.text_document_position)?; let line_index = snap.file_line_index(position.file_id)?; // in `ide`, the `on_type` invariant is that // `text.char_at(position) == typed_char`. position.offset -= TextSize::of('.'); - let char_typed = params.ch.chars().next().unwrap_or('\0'); let text = snap.analysis.file_text(position.file_id)?; if stdx::never!(!text[usize::from(position.offset)..].starts_with(char_typed)) { return Ok(None); } - // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`, - // but it requires precise cursor positioning to work, and one can't - // position the cursor with on_type formatting. So, let's just toggle this - // feature off here, hoping that we'll enable it one day, 😿. - if char_typed == '>' { - return Ok(None); - } - let chars_to_exclude = snap.config.typing_exclude_chars(); - - let edit = snap.analysis.on_char_typed(position, char_typed, chars_to_exclude)?; + let edit = snap.analysis.on_char_typed(position, char_typed)?; let edit = match edit { Some(it) => it, None => return Ok(None), diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs index e7f5a7f5e78..61ec576dd4f 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs @@ -47,7 +47,8 @@ use self::lsp::ext as lsp_ext; #[cfg(test)] mod integrated_benchmarks; -use ide::{CompletionItem, CompletionRelevance}; +use hir::Mutability; +use ide::{CompletionItem, CompletionItemRefMode, CompletionRelevance}; use serde::de::DeserializeOwned; use tenthash::TentHasher; @@ -132,8 +133,13 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; hasher.update(detail); } hash_completion_relevance(&mut hasher, &item.relevance); - if let Some((mutability, text_size)) = &item.ref_match { - hasher.update(mutability.as_keyword_for_ref()); + if let Some((ref_mode, text_size)) = &item.ref_match { + let prefix = match ref_mode { + CompletionItemRefMode::Reference(Mutability::Shared) => "&", + CompletionItemRefMode::Reference(Mutability::Mut) => "&mut ", + CompletionItemRefMode::Dereference => "*", + }; + hasher.update(prefix); hasher.update(u32::from(*text_size).to_le_bytes()); } for (import_path, import_name) in &item.import_to_add { diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs index f50cbba7acf..134de92feab 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs @@ -108,19 +108,18 @@ impl Request for RebuildProcMacros { const METHOD: &'static str = "rust-analyzer/rebuildProcMacros"; } -pub enum SyntaxTree {} +pub enum ViewSyntaxTree {} -impl Request for SyntaxTree { - type Params = SyntaxTreeParams; +impl Request for ViewSyntaxTree { + type Params = ViewSyntaxTreeParams; type Result = String; - const METHOD: &'static str = "rust-analyzer/syntaxTree"; + const METHOD: &'static str = "rust-analyzer/viewSyntaxTree"; } #[derive(Deserialize, Serialize, Debug)] #[serde(rename_all = "camelCase")] -pub struct SyntaxTreeParams { +pub struct ViewSyntaxTreeParams { pub text_document: TextDocumentIdentifier, - pub range: Option<Range>, } pub enum ViewHir {} diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs index fe4d02dcb4f..a5516e7f9d4 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs @@ -547,7 +547,18 @@ pub(crate) fn inlay_hint( file_id: FileId, mut inlay_hint: InlayHint, ) -> Cancellable<lsp_types::InlayHint> { - let resolve_range_and_hash = inlay_hint.needs_resolve().map(|range| { + let hint_needs_resolve = |hint: &InlayHint| -> Option<TextRange> { + hint.resolve_parent.filter(|_| { + hint.text_edit.is_some() + || hint + .label + .parts + .iter() + .any(|part| part.linked_location.is_some() || part.tooltip.is_some()) + }) + }; + + let resolve_range_and_hash = hint_needs_resolve(&inlay_hint).map(|range| { ( range, std::hash::BuildHasher::hash_one( @@ -568,7 +579,11 @@ pub(crate) fn inlay_hint( something_to_resolve |= inlay_hint.text_edit.is_some(); None } else { - inlay_hint.text_edit.take().map(|it| text_edit_vec(line_index, it)) + inlay_hint + .text_edit + .take() + .and_then(|it| it.computed()) + .map(|it| text_edit_vec(line_index, it)) }; let (label, tooltip) = inlay_hint_label( snap, @@ -626,7 +641,7 @@ fn inlay_hint_label( *something_to_resolve |= tooltip.is_some(); None } else { - match tooltip { + match tooltip.and_then(|it| it.computed()) { Some(ide::InlayTooltip::String(s)) => { Some(lsp_types::InlayHintTooltip::String(s)) } @@ -650,7 +665,7 @@ fn inlay_hint_label( *something_to_resolve |= part.tooltip.is_some(); None } else { - match part.tooltip { + match part.tooltip.and_then(|it| it.computed()) { Some(ide::InlayTooltip::String(s)) => { Some(lsp_types::InlayHintLabelPartTooltip::String(s)) } @@ -1993,7 +2008,7 @@ fn bar(_: usize) {} #[track_caller] fn check_rendered_snippets_in_source( - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, edit: TextEdit, snippets: SnippetEdit, expect: Expect, diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs index 97657b92658..d6dc8b521fd 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs @@ -1145,7 +1145,7 @@ impl GlobalState { .on::<RETRY, lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol) .on::<NO_RETRY, lsp_ext::Ssr>(handlers::handle_ssr) .on::<NO_RETRY, lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout) - .on::<NO_RETRY, lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) + .on::<NO_RETRY, lsp_ext::ViewSyntaxTree>(handlers::handle_view_syntax_tree) .on::<NO_RETRY, lsp_ext::ViewHir>(handlers::handle_view_hir) .on::<NO_RETRY, lsp_ext::ViewMir>(handlers::handle_view_mir) .on::<NO_RETRY, lsp_ext::InterpretFunction>(handlers::handle_interpret_function) diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs index 503b3ee43a1..3edfb812cf5 100644 --- a/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs +++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/test_runner.rs @@ -18,7 +18,11 @@ pub(crate) enum TestState { Started, Ok, Ignored, - Failed { stdout: String }, + Failed { + // the stdout field is not always present depending on cargo test flags + #[serde(skip_serializing_if = "String::is_empty", default)] + stdout: String, + }, } #[derive(Debug, Deserialize)] diff --git a/src/tools/rust-analyzer/crates/span/src/hygiene.rs b/src/tools/rust-analyzer/crates/span/src/hygiene.rs index 87a948df550..6becc8e41ed 100644 --- a/src/tools/rust-analyzer/crates/span/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/span/src/hygiene.rs @@ -26,7 +26,7 @@ use crate::InternId; #[cfg(feature = "ra-salsa")] use ra_salsa::{InternId, InternValue}; -use crate::MacroCallId; +use crate::{Edition, MacroCallId}; /// Interned [`SyntaxContextData`]. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -59,11 +59,20 @@ impl fmt::Display for SyntaxContextId { } impl SyntaxContextId { + #[inline] + pub fn remove_root_edition(&mut self) { + if self.is_root() { + *self = Self::root(Edition::Edition2015); + } + } + /// The root context, which is the parent of all other contexts. All [`FileId`]s have this context. - pub const ROOT: Self = SyntaxContextId(unsafe { InternId::new_unchecked(0) }); + pub const fn root(edition: Edition) -> Self { + SyntaxContextId(unsafe { InternId::new_unchecked(edition as u32) }) + } pub fn is_root(self) -> bool { - self == Self::ROOT + self.into_u32() <= Edition::LATEST as u32 } /// Deconstruct a `SyntaxContextId` into a raw `u32`. @@ -89,6 +98,7 @@ pub struct SyntaxContextData { // per crate. Though that is likely not a problem as `MacroCallId`s are already crate calling dependent. pub outer_expn: Option<MacroCallId>, pub outer_transparency: Transparency, + pub edition: Edition, pub parent: SyntaxContextId, /// This context, but with all transparent and semi-transparent expansions filtered away. pub opaque: SyntaxContextId, @@ -98,10 +108,10 @@ pub struct SyntaxContextData { #[cfg(feature = "ra-salsa")] impl InternValue for SyntaxContextData { - type Key = (SyntaxContextId, Option<MacroCallId>, Transparency); + type Key = (SyntaxContextId, Option<MacroCallId>, Transparency, Edition); fn into_key(&self) -> Self::Key { - (self.parent, self.outer_expn, self.outer_transparency) + (self.parent, self.outer_expn, self.outer_transparency, self.edition) } } @@ -118,13 +128,14 @@ impl std::fmt::Debug for SyntaxContextData { } impl SyntaxContextData { - pub fn root() -> Self { + pub fn root(edition: Edition) -> Self { SyntaxContextData { outer_expn: None, outer_transparency: Transparency::Opaque, - parent: SyntaxContextId::ROOT, - opaque: SyntaxContextId::ROOT, - opaque_and_semitransparent: SyntaxContextId::ROOT, + parent: SyntaxContextId::root(edition), + opaque: SyntaxContextId::root(edition), + opaque_and_semitransparent: SyntaxContextId::root(edition), + edition, } } } diff --git a/src/tools/rust-analyzer/crates/span/src/map.rs b/src/tools/rust-analyzer/crates/span/src/map.rs index 66bbce18594..dc35de67fd8 100644 --- a/src/tools/rust-analyzer/crates/span/src/map.rs +++ b/src/tools/rust-analyzer/crates/span/src/map.rs @@ -208,7 +208,7 @@ impl RealSpanMap { Span { range: range - offset, anchor: SpanAnchor { file_id: self.file_id, ast_id }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(self.file_id.edition()), } } } diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml index bf0d6df9ad8..1ebb48c577a 100644 --- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml +++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml @@ -23,7 +23,7 @@ itertools.workspace = true [target.'cfg(windows)'.dependencies] miow = "0.6.0" -windows-sys = { version = "0.52", features = ["Win32_Foundation"] } +windows-sys = { version = "0.59", features = ["Win32_Foundation"] } [features] # Uncomment to enable for the whole crate graph diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs index ed8b1908d60..19801c49e43 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs @@ -1,6 +1,6 @@ //! Conversions between [`SyntaxNode`] and [`tt::TokenTree`]. -use std::fmt; +use std::{fmt, hash::Hash}; use intern::Symbol; use rustc_hash::{FxHashMap, FxHashSet}; @@ -58,7 +58,7 @@ pub mod dummy_test_span_utils { ), ast_id: span::ROOT_ERASED_FILE_AST_ID, }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), }; pub struct DummyTestSpanMap; @@ -74,7 +74,7 @@ pub mod dummy_test_span_utils { ), ast_id: span::ROOT_ERASED_FILE_AST_ID, }, - ctx: SyntaxContextId::ROOT, + ctx: SyntaxContextId::root(Edition::CURRENT), } } } @@ -141,15 +141,16 @@ where pub fn token_tree_to_syntax_node<Ctx>( tt: &tt::TopSubtree<SpanData<Ctx>>, entry_point: parser::TopEntryPoint, - edition: parser::Edition, + span_to_edition: &mut dyn FnMut(Ctx) -> Edition, + top_edition: Edition, ) -> (Parse<SyntaxNode>, SpanMap<Ctx>) where - SpanData<Ctx>: Copy + fmt::Debug, - Ctx: PartialEq, + Ctx: Copy + fmt::Debug + PartialEq + PartialEq + Eq + Hash, { let buffer = tt.view().strip_invisible(); - let parser_input = to_parser_input(edition, buffer); - let parser_output = entry_point.parse(&parser_input, edition); + let parser_input = to_parser_input(buffer, span_to_edition); + // It matters what edition we parse with even when we escape all identifiers correctly. + let parser_output = entry_point.parse(&parser_input, top_edition); let mut tree_sink = TtTreeSink::new(buffer.cursor()); for event in parser_output.iter() { match event { diff --git a/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs b/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs index 1bbb05f5507..0dcb2be316c 100644 --- a/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs +++ b/src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs @@ -2,17 +2,20 @@ //! format that works for our parser. use std::fmt; +use std::hash::Hash; -use span::Edition; +use rustc_hash::FxHashMap; +use span::{Edition, SpanData}; use syntax::{SyntaxKind, SyntaxKind::*, T}; -pub fn to_parser_input<S: Copy + fmt::Debug>( - edition: Edition, - buffer: tt::TokenTreesView<'_, S>, +pub fn to_parser_input<Ctx: Copy + fmt::Debug + PartialEq + Eq + Hash>( + buffer: tt::TokenTreesView<'_, SpanData<Ctx>>, + span_to_edition: &mut dyn FnMut(Ctx) -> Edition, ) -> parser::Input { let mut res = parser::Input::default(); let mut current = buffer.cursor(); + let mut syntax_context_to_edition_cache = FxHashMap::default(); while !current.eof() { let tt = current.token_tree(); @@ -57,20 +60,25 @@ pub fn to_parser_input<S: Copy + fmt::Debug>( res.was_joint(); } } - tt::Leaf::Ident(ident) => match ident.sym.as_str() { - "_" => res.push(T![_]), - i if i.starts_with('\'') => res.push(LIFETIME_IDENT), - _ if ident.is_raw.yes() => res.push(IDENT), - text => match SyntaxKind::from_keyword(text, edition) { - Some(kind) => res.push(kind), - None => { - let contextual_keyword = - SyntaxKind::from_contextual_keyword(text, edition) - .unwrap_or(SyntaxKind::IDENT); - res.push_ident(contextual_keyword); - } - }, - }, + tt::Leaf::Ident(ident) => { + let edition = *syntax_context_to_edition_cache + .entry(ident.span.ctx) + .or_insert_with(|| span_to_edition(ident.span.ctx)); + match ident.sym.as_str() { + "_" => res.push(T![_]), + i if i.starts_with('\'') => res.push(LIFETIME_IDENT), + _ if ident.is_raw.yes() => res.push(IDENT), + text => match SyntaxKind::from_keyword(text, edition) { + Some(kind) => res.push(kind), + None => { + let contextual_keyword = + SyntaxKind::from_contextual_keyword(text, edition) + .unwrap_or(SyntaxKind::IDENT); + res.push_ident(contextual_keyword); + } + }, + } + } tt::Leaf::Punct(punct) => { let kind = SyntaxKind::from_char(punct.char) .unwrap_or_else(|| panic!("{punct:#?} is not a valid punct")); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs index de40d638be3..579f3ba8b4f 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit.rs @@ -153,8 +153,8 @@ impl<N: AstNode + Clone> AstNodeEdit for N {} #[test] fn test_increase_indent() { let arm_list = { - let arm = make::match_arm(iter::once(make::wildcard_pat().into()), None, make::expr_unit()); - make::match_arm_list(vec![arm.clone(), arm]) + let arm = make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_unit()); + make::match_arm_list([arm.clone(), arm]) }; assert_eq!( arm_list.syntax().to_string(), diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs index 9466755576b..93faeb40c32 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/expr_ext.rs @@ -10,7 +10,7 @@ use crate::{ FormatArgsArg, FormatArgsExpr, MacroDef, Static, TokenTree, }, AstToken, - SyntaxKind::*, + SyntaxKind::{self, *}, SyntaxNode, SyntaxToken, T, }; @@ -50,6 +50,27 @@ impl From<ast::IfExpr> for ElseBranch { } } +impl AstNode for ElseBranch { + fn can_cast(kind: SyntaxKind) -> bool { + ast::BlockExpr::can_cast(kind) || ast::IfExpr::can_cast(kind) + } + + fn cast(syntax: SyntaxNode) -> Option<Self> { + if let Some(block_expr) = ast::BlockExpr::cast(syntax.clone()) { + Some(Self::Block(block_expr)) + } else { + ast::IfExpr::cast(syntax).map(Self::IfExpr) + } + } + + fn syntax(&self) -> &SyntaxNode { + match self { + ElseBranch::Block(block_expr) => block_expr.syntax(), + ElseBranch::IfExpr(if_expr) => if_expr.syntax(), + } + } +} + impl ast::IfExpr { pub fn condition(&self) -> Option<ast::Expr> { // If the condition is a BlockExpr, check if the then body is missing. diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs index 282cbc4b3a4..dca231604fa 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs @@ -63,6 +63,9 @@ pub mod ext { Some(expr) } + pub fn expr_unit() -> ast::Expr { + expr_tuple([]).into() + } pub fn expr_unreachable() -> ast::Expr { expr_from_text("unreachable!()") } @@ -546,10 +549,6 @@ pub fn hacky_block_expr( ast_from_text(&format!("fn f() {buf}")) } -pub fn expr_unit() -> ast::Expr { - expr_from_text("()") -} - pub fn expr_literal(text: &str) -> ast::Literal { assert_eq!(text.trim(), text); ast_from_text(&format!("fn f() {{ let _ = {text}; }}")) @@ -559,8 +558,8 @@ pub fn expr_const_value(text: &str) -> ast::ConstArg { ast_from_text(&format!("trait Foo<const N: usize = {text}> {{}}")) } -pub fn expr_empty_block() -> ast::Expr { - expr_from_text("{}") +pub fn expr_empty_block() -> ast::BlockExpr { + ast_from_text("const C: () = {};") } pub fn expr_path(path: ast::Path) -> ast::Expr { expr_from_text(&path.to_string()) @@ -600,14 +599,14 @@ pub fn expr_try(expr: ast::Expr) -> ast::Expr { pub fn expr_await(expr: ast::Expr) -> ast::Expr { expr_from_text(&format!("{expr}.await")) } -pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr { +pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr { expr_from_text(&format!("match {expr} {match_arm_list}")) } pub fn expr_if( condition: ast::Expr, then_branch: ast::BlockExpr, else_branch: Option<ast::ElseBranch>, -) -> ast::Expr { +) -> ast::IfExpr { let else_branch = match else_branch { Some(ast::ElseBranch::Block(block)) => format!("else {block}"), Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"), @@ -623,7 +622,7 @@ pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr { expr_from_text(&format!("loop {block}")) } -pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr { +pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::PrefixExpr { let token = token(op); expr_from_text(&format!("{token}{expr}")) } @@ -656,14 +655,14 @@ pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr { pub fn expr_paren(expr: ast::Expr) -> ast::Expr { expr_from_text(&format!("({expr})")) } -pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::Expr { +pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr { let expr = elements.into_iter().format(", "); expr_from_text(&format!("({expr})")) } pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr { expr_from_text(&format!("{lhs} = {rhs}")) } -fn expr_from_text(text: &str) -> ast::Expr { +fn expr_from_text<E: Into<ast::Expr> + AstNode>(text: &str) -> E { ast_from_text(&format!("const C: () = {text};")) } pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { @@ -788,15 +787,21 @@ pub fn path_pat(path: ast::Path) -> ast::Pat { } } -pub fn match_arm( - pats: impl IntoIterator<Item = ast::Pat>, - guard: Option<ast::Expr>, - expr: ast::Expr, -) -> ast::MatchArm { - let pats_str = pats.into_iter().join(" | "); +/// Returns a `Pat` if the path has just one segment, an `OrPat` otherwise. +pub fn or_pat(pats: impl IntoIterator<Item = ast::Pat>, leading_pipe: bool) -> ast::Pat { + let leading_pipe = if leading_pipe { "| " } else { "" }; + let pats = pats.into_iter().join(" | "); + + return from_text(&format!("{leading_pipe}{pats}")); + fn from_text(text: &str) -> ast::Pat { + ast_from_text(&format!("fn f({text}: ())")) + } +} + +pub fn match_arm(pat: ast::Pat, guard: Option<ast::MatchGuard>, expr: ast::Expr) -> ast::MatchArm { return match guard { - Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")), - None => from_text(&format!("{pats_str} => {expr}")), + Some(guard) => from_text(&format!("{pat} {guard} => {expr}")), + None => from_text(&format!("{pat} => {expr}")), }; fn from_text(text: &str) -> ast::MatchArm { @@ -817,6 +822,14 @@ pub fn match_arm_with_guard( } } +pub fn match_guard(condition: ast::Expr) -> ast::MatchGuard { + return from_text(&format!("if {condition}")); + + fn from_text(text: &str) -> ast::MatchGuard { + ast_from_text(&format!("fn f() {{ match () {{() {text} => () }}")) + } +} + pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList { let arms_str = arms.into_iter().fold(String::new(), |mut acc, arm| { let needs_comma = arm.expr().is_none_or(|it| !it.is_block_like()); diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs index 81c7e15bcbc..56f94b965e3 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs @@ -185,6 +185,14 @@ impl ast::Attr { Some((self.simple_name()?, tt)) } + pub fn as_simple_path(&self) -> Option<ast::Path> { + let meta = self.meta()?; + if meta.eq_token().is_some() || meta.token_tree().is_some() { + return None; + } + self.path() + } + pub fn simple_name(&self) -> Option<SmolStr> { let path = self.meta()?.path()?; match (path.segment(), path.qualifier()) { diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs index bea6bfeafcf..572622db544 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs @@ -1,6 +1,9 @@ //! Wrappers over [`make`] constructors use crate::{ - ast::{self, make, HasGenericParams, HasName, HasTypeBounds, HasVisibility}, + ast::{ + self, make, HasArgList, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds, + HasVisibility, + }, syntax_editor::SyntaxMappingBuilder, AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken, }; @@ -12,6 +15,14 @@ impl SyntaxFactory { make::name(name).clone_for_update() } + pub fn name_ref(&self, name: &str) -> ast::NameRef { + make::name_ref(name).clone_for_update() + } + + pub fn lifetime(&self, text: &str) -> ast::Lifetime { + make::lifetime(text).clone_for_update() + } + pub fn ty(&self, text: &str) -> ast::Type { make::ty(text).clone_for_update() } @@ -24,6 +35,20 @@ impl SyntaxFactory { ast } + pub fn ty_path(&self, path: ast::Path) -> ast::PathType { + let ast::Type::PathType(ast) = make::ty_path(path.clone()).clone_for_update() else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn type_param( &self, name: ast::Name, @@ -46,6 +71,71 @@ impl SyntaxFactory { ast } + pub fn path_segment(&self, name_ref: ast::NameRef) -> ast::PathSegment { + let ast = make::path_segment(name_ref.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn path_segment_generics( + &self, + name_ref: ast::NameRef, + generic_arg_list: ast::GenericArgList, + ) -> ast::PathSegment { + let ast::Type::PathType(path) = make::ty(&format!("{name_ref}{generic_arg_list}")) else { + unreachable!(); + }; + + let ast = path.path().unwrap().segment().unwrap().clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone()); + builder.map_node( + generic_arg_list.syntax().clone(), + ast.generic_arg_list().unwrap().syntax().clone(), + ); + builder.finish(&mut mapping); + } + + ast + } + + pub fn path_unqualified(&self, segment: ast::PathSegment) -> ast::Path { + let ast = make::path_unqualified(segment.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(segment.syntax().clone(), ast.segment().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn path_from_segments( + &self, + segments: impl IntoIterator<Item = ast::PathSegment>, + is_abs: bool, + ) -> ast::Path { + let (segments, input) = iterator_input(segments); + let ast = make::path_from_segments(segments, is_abs).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input.into_iter(), ast.segments().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat { let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update(); @@ -58,6 +148,32 @@ impl SyntaxFactory { ast } + pub fn wildcard_pat(&self) -> ast::WildcardPat { + make::wildcard_pat().clone_for_update() + } + + pub fn literal_pat(&self, text: &str) -> ast::LiteralPat { + make::literal_pat(text).clone_for_update() + } + + pub fn tuple_struct_pat( + &self, + path: ast::Path, + fields: impl IntoIterator<Item = ast::Pat>, + ) -> ast::TupleStructPat { + let (fields, input) = iterator_input(fields); + let ast = make::tuple_struct_pat(path.clone(), fields).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone()); + builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn block_expr( &self, statements: impl IntoIterator<Item = ast::Stmt>, @@ -95,7 +211,20 @@ impl SyntaxFactory { } pub fn expr_empty_block(&self) -> ast::BlockExpr { - ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() } + make::expr_empty_block().clone_for_update() + } + + pub fn expr_tuple(&self, fields: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr { + let (fields, input) = iterator_input(fields); + let ast = make::expr_tuple(fields).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast } pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr { @@ -115,6 +244,10 @@ impl SyntaxFactory { ast } + pub fn expr_literal(&self, text: &str) -> ast::Literal { + make::expr_literal(text).clone_for_update() + } + pub fn expr_path(&self, path: ast::Path) -> ast::Expr { let ast::Expr::PathExpr(ast) = make::expr_path(path.clone()).clone_for_update() else { unreachable!() @@ -129,6 +262,49 @@ impl SyntaxFactory { ast.into() } + pub fn expr_prefix(&self, op: SyntaxKind, expr: ast::Expr) -> ast::PrefixExpr { + let ast = make::expr_prefix(op, expr.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_call(&self, expr: ast::Expr, arg_list: ast::ArgList) -> ast::CallExpr { + // FIXME: `make::expr_call`` should return a `CallExpr`, not just an `Expr` + let ast::Expr::CallExpr(ast) = + make::expr_call(expr.clone(), arg_list.clone()).clone_for_update() + else { + unreachable!() + }; + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.map_node(arg_list.syntax().clone(), ast.arg_list().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn arg_list(&self, args: impl IntoIterator<Item = ast::Expr>) -> ast::ArgList { + let (args, input) = iterator_input(args); + let ast = make::arg_list(args).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax.clone()); + builder.map_children(input.into_iter(), ast.args().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn expr_ref(&self, expr: ast::Expr, exclusive: bool) -> ast::Expr { let ast::Expr::RefExpr(ast) = make::expr_ref(expr.clone(), exclusive).clone_for_update() else { @@ -160,6 +336,125 @@ impl SyntaxFactory { ast } + pub fn expr_if( + &self, + condition: ast::Expr, + then_branch: ast::BlockExpr, + else_branch: Option<ast::ElseBranch>, + ) -> ast::IfExpr { + let ast = make::expr_if(condition.clone(), then_branch.clone(), else_branch.clone()) + .clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone()); + builder.map_node( + then_branch.syntax().clone(), + ast.then_branch().unwrap().syntax().clone(), + ); + + if let Some(else_branch) = else_branch { + builder.map_node( + else_branch.syntax().clone(), + ast.else_branch().unwrap().syntax().clone(), + ); + } + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_let(&self, pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr { + let ast = make::expr_let(pattern.clone(), expr.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_stmt(&self, expr: ast::Expr) -> ast::ExprStmt { + let ast = make::expr_stmt(expr.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn expr_match(&self, expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr { + let ast = make::expr_match(expr.clone(), match_arm_list.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.map_node( + match_arm_list.syntax().clone(), + ast.match_arm_list().unwrap().syntax().clone(), + ); + builder.finish(&mut mapping); + } + + ast + } + + pub fn match_arm( + &self, + pat: ast::Pat, + guard: Option<ast::MatchGuard>, + expr: ast::Expr, + ) -> ast::MatchArm { + let ast = make::match_arm(pat.clone(), guard.clone(), expr.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone()); + if let Some(guard) = guard { + builder.map_node(guard.syntax().clone(), ast.guard().unwrap().syntax().clone()); + } + builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn match_guard(&self, condition: ast::Expr) -> ast::MatchGuard { + let ast = make::match_guard(condition.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn match_arm_list( + &self, + match_arms: impl IntoIterator<Item = ast::MatchArm>, + ) -> ast::MatchArmList { + let (match_arms, input) = iterator_input(match_arms); + let ast = make::match_arm_list(match_arms).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_children(input.into_iter(), ast.arms().map(|it| it.syntax().clone())); + builder.finish(&mut mapping); + } + + ast + } + pub fn let_stmt( &self, pattern: ast::Pat, @@ -185,6 +480,30 @@ impl SyntaxFactory { ast } + pub fn type_arg(&self, ty: ast::Type) -> ast::TypeArg { + let ast = make::type_arg(ty.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(ty.syntax().clone(), ast.ty().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + + pub fn lifetime_arg(&self, lifetime: ast::Lifetime) -> ast::LifetimeArg { + let ast = make::lifetime_arg(lifetime.clone()).clone_for_update(); + + if let Some(mut mapping) = self.mappings() { + let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); + builder.map_node(lifetime.syntax().clone(), ast.lifetime().unwrap().syntax().clone()); + builder.finish(&mut mapping); + } + + ast + } + pub fn item_const( &self, visibility: Option<ast::Visibility>, @@ -252,12 +571,17 @@ impl SyntaxFactory { ast } - pub fn turbofish_generic_arg_list( + pub fn generic_arg_list( &self, generic_args: impl IntoIterator<Item = ast::GenericArg>, + is_turbo: bool, ) -> ast::GenericArgList { let (generic_args, input) = iterator_input(generic_args); - let ast = make::turbofish_generic_arg_list(generic_args.clone()).clone_for_update(); + let ast = if is_turbo { + make::turbofish_generic_arg_list(generic_args).clone_for_update() + } else { + make::generic_arg_list(generic_args).clone_for_update() + }; if let Some(mut mapping) = self.mappings() { let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone()); @@ -503,11 +827,41 @@ impl SyntaxFactory { make::token(kind) } - pub fn whitespace(&self, text: &str) -> ast::SyntaxToken { + pub fn whitespace(&self, text: &str) -> SyntaxToken { make::tokens::whitespace(text) } } +// `ext` constructors +impl SyntaxFactory { + pub fn ident_path(&self, ident: &str) -> ast::Path { + self.path_unqualified(self.path_segment(self.name_ref(ident))) + } + + pub fn expr_unit(&self) -> ast::Expr { + self.expr_tuple([]).into() + } + + pub fn ty_option(&self, t: ast::Type) -> ast::PathType { + let generic_arg_list = self.generic_arg_list([self.type_arg(t).into()], false); + let path = self.path_unqualified( + self.path_segment_generics(self.name_ref("Option"), generic_arg_list), + ); + + self.ty_path(path) + } + + pub fn ty_result(&self, t: ast::Type, e: ast::Type) -> ast::PathType { + let generic_arg_list = + self.generic_arg_list([self.type_arg(t).into(), self.type_arg(e).into()], false); + let path = self.path_unqualified( + self.path_segment_generics(self.name_ref("Result"), generic_arg_list), + ); + + self.ty_path(path) + } +} + // We need to collect `input` here instead of taking `impl IntoIterator + Clone`, // because if we took `impl IntoIterator + Clone`, that could be something like an // `Iterator::map` with a closure that also makes use of a `SyntaxFactory` constructor. diff --git a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs index 992a847663a..b82181ae13a 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/syntax_editor.rs @@ -335,7 +335,7 @@ mod tests { #[test] fn basic_usage() { let root = make::match_arm( - [make::wildcard_pat().into()], + make::wildcard_pat().into(), None, make::expr_tuple([ make::expr_bin_op( @@ -344,7 +344,8 @@ mod tests { make::expr_literal("2").into(), ), make::expr_literal("true").into(), - ]), + ]) + .into(), ); let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap(); @@ -549,7 +550,7 @@ mod tests { None, None, make::param_list(None, []), - make::block_expr([], Some(make::expr_unit())), + make::block_expr([], Some(make::ext::expr_unit())), Some(make::ret_type(make::ty_unit())), false, false, diff --git a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml index c860e7b1183..95f4cb9d67e 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml +++ b/src/tools/rust-analyzer/crates/test-fixture/Cargo.toml @@ -2,6 +2,8 @@ name = "test-fixture" version = "0.0.0" rust-version.workspace = true +description = "Test fixtures for rust-analyzer." + edition.workspace = true license.workspace = true authors.workspace = true diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs index 0e72d796875..866379d940e 100644 --- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs +++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs @@ -30,7 +30,9 @@ pub const WORKSPACE: base_db::SourceRootId = base_db::SourceRootId(0); pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static { #[track_caller] - fn with_single_file(ra_fixture: &str) -> (Self, EditionedFileId) { + fn with_single_file( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + ) -> (Self, EditionedFileId) { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); fixture.change.apply(&mut db); @@ -39,7 +41,9 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static { } #[track_caller] - fn with_many_files(ra_fixture: &str) -> (Self, Vec<EditionedFileId>) { + fn with_many_files( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + ) -> (Self, Vec<EditionedFileId>) { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); fixture.change.apply(&mut db); @@ -48,7 +52,7 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static { } #[track_caller] - fn with_files(ra_fixture: &str) -> Self { + fn with_files(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> Self { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); fixture.change.apply(&mut db); @@ -58,7 +62,7 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static { #[track_caller] fn with_files_extra_proc_macros( - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, proc_macros: Vec<(String, ProcMacro)>, ) -> Self { let fixture = ChangeFixture::parse_with_proc_macros(ra_fixture, proc_macros); @@ -69,21 +73,23 @@ pub trait WithFixture: Default + ExpandDatabase + SourceRootDatabase + 'static { } #[track_caller] - fn with_position(ra_fixture: &str) -> (Self, FilePosition) { + fn with_position(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Self, FilePosition) { let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); let offset = range_or_offset.expect_offset(); (db, FilePosition { file_id, offset }) } #[track_caller] - fn with_range(ra_fixture: &str) -> (Self, FileRange) { + fn with_range(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (Self, FileRange) { let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); let range = range_or_offset.expect_range(); (db, FileRange { file_id, range }) } #[track_caller] - fn with_range_or_offset(ra_fixture: &str) -> (Self, EditionedFileId, RangeOrOffset) { + fn with_range_or_offset( + #[rust_analyzer::rust_fixture] ra_fixture: &str, + ) -> (Self, EditionedFileId, RangeOrOffset) { let fixture = ChangeFixture::parse(ra_fixture); let mut db = Self::default(); fixture.change.apply(&mut db); @@ -116,12 +122,12 @@ pub struct ChangeFixture { const SOURCE_ROOT_PREFIX: &str = "/"; impl ChangeFixture { - pub fn parse(ra_fixture: &str) -> ChangeFixture { + pub fn parse(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> ChangeFixture { Self::parse_with_proc_macros(ra_fixture, Vec::new()) } pub fn parse_with_proc_macros( - ra_fixture: &str, + #[rust_analyzer::rust_fixture] ra_fixture: &str, mut proc_macro_defs: Vec<(String, ProcMacro)>, ) -> ChangeFixture { let FixtureWithProjectMeta { @@ -376,8 +382,8 @@ impl ChangeFixture { } } -fn default_test_proc_macros() -> [(String, ProcMacro); 8] { - [ +fn default_test_proc_macros() -> Box<[(String, ProcMacro)]> { + Box::new([ ( r#" #[proc_macro_attribute] @@ -498,7 +504,22 @@ pub fn issue_17479(input: TokenStream) -> TokenStream { disabled: false, }, ), - ] + ( + r#" +#[proc_macro_attribute] +pub fn issue_18898(_attr: TokenStream, input: TokenStream) -> TokenStream { + input +} +"# + .into(), + ProcMacro { + name: Symbol::intern("issue_18898"), + kind: ProcMacroKind::Bang, + expander: sync::Arc::new(Issue18898ProcMacroExpander), + disabled: false, + }, + ), + ]) } fn filter_test_proc_macros( @@ -801,3 +822,54 @@ impl ProcMacroExpander for Issue17479ProcMacroExpander { }) } } + +// Reads ident type within string quotes, for issue #17479. +#[derive(Debug)] +struct Issue18898ProcMacroExpander; +impl ProcMacroExpander for Issue18898ProcMacroExpander { + fn expand( + &self, + subtree: &TopSubtree, + _: Option<&TopSubtree>, + _: &Env, + def_site: Span, + _: Span, + _: Span, + _: Option<String>, + ) -> Result<TopSubtree, ProcMacroExpansionError> { + let span = subtree + .token_trees() + .flat_tokens() + .last() + .ok_or_else(|| ProcMacroExpansionError::Panic("malformed input".to_owned()))? + .first_span(); + let overly_long_subtree = quote! {span => + { + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + let a = 5; + } + }; + Ok(quote! { def_site => + fn foo() { + #overly_long_subtree + } + }) + } +} diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs index 54c9db7aacc..7fe26d53bf2 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs @@ -168,7 +168,7 @@ impl FixtureWithProjectMeta { /// That will set toolchain to nightly and include predefined proc macros and a subset of /// `libcore` into the fixture, see `minicore.rs` for what's available. Note that toolchain /// defaults to stable. - pub fn parse(ra_fixture: &str) -> Self { + pub fn parse(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> Self { let fixture = trim_indent(ra_fixture); let mut fixture = fixture.as_str(); let mut toolchain = None; diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs index 4a2346193b4..fd06736a252 100644 --- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs +++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs @@ -32,7 +32,7 @@ //! error: fmt //! fmt: option, result, transmute, coerce_unsized, copy, clone, derive //! fn: tuple -//! from: sized +//! from: sized, result //! future: pin //! coroutine: pin //! dispatch_from_dyn: unsize, pin @@ -332,6 +332,25 @@ pub mod convert { t } } + + pub trait TryFrom<T>: Sized { + type Error; + fn try_from(value: T) -> Result<Self, Self::Error>; + } + pub trait TryInto<T>: Sized { + type Error; + fn try_into(self) -> Result<T, Self::Error>; + } + + impl<T, U> TryInto<U> for T + where + U: TryFrom<T>, + { + type Error = U::Error; + fn try_into(self) -> Result<U, U::Error> { + U::try_from(self) + } + } // endregion:from // region:as_ref @@ -1510,7 +1529,7 @@ pub mod iter { impl<T, const N: usize> IntoIterator for [T; N] { type Item = T; type IntoIter = IntoIter<T, N>; - fn into_iter(self) -> I { + fn into_iter(self) -> Self::IntoIter { IntoIter { data: self, range: IndexRange { start: 0, end: loop {} } } } } @@ -1520,6 +1539,29 @@ pub mod iter { loop {} } } + pub struct Iter<'a, T> { + slice: &'a [T], + } + impl<'a, T> IntoIterator for &'a [T; N] { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + loop {} + } + } + impl<'a, T> IntoIterator for &'a [T] { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + fn into_iter(self) -> Self::IntoIter { + loop {} + } + } + impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + fn next(&mut self) -> Option<T> { + loop {} + } + } } pub use self::collect::IntoIterator; } @@ -1532,6 +1574,15 @@ pub mod str { pub const unsafe fn from_utf8_unchecked(v: &[u8]) -> &str { "" } + pub trait FromStr: Sized { + type Err; + fn from_str(s: &str) -> Result<Self, Self::Err>; + } + impl str { + pub fn parse<F: FromStr>(&self) -> Result<F, F::Err> { + FromStr::from_str(self) + } + } } // endregion:str @@ -1791,7 +1842,7 @@ pub mod prelude { cmp::{Eq, PartialEq}, // :eq cmp::{Ord, PartialOrd}, // :ord convert::AsRef, // :as_ref - convert::{From, Into}, // :from + convert::{From, Into, TryFrom, TryInto}, // :from default::Default, // :default iter::{IntoIterator, Iterator}, // :iterator macros::builtin::{derive, derive_const}, // :derive @@ -1806,6 +1857,7 @@ pub mod prelude { option::Option::{self, None, Some}, // :option panic, // :panic result::Result::{self, Err, Ok}, // :result + str::FromStr, // :str }; } diff --git a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml index 09296dc6dd5..bc54d7168f0 100644 --- a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml +++ b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml @@ -16,7 +16,7 @@ doctest = false tracing.workspace = true walkdir = "2.3.2" crossbeam-channel.workspace = true -notify = "6.1.1" +notify = "8.0.0" rayon = "1.10.0" stdx.workspace = true diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md index cd0f49174cd..3ba492e0959 100644 --- a/src/tools/rust-analyzer/docs/dev/README.md +++ b/src/tools/rust-analyzer/docs/dev/README.md @@ -154,19 +154,21 @@ There are also several VS Code commands which might be of interest: * `rust-analyzer: Status` shows some memory-usage statistics. -* `rust-analyzer: Syntax Tree` shows syntax tree of the current file/selection. - * `rust-analyzer: View Hir` shows the HIR expressions within the function containing the cursor. - You can hover over syntax nodes in the opened text file to see the appropriate - rust code that it refers to and the rust editor will also highlight the proper - text range. +* If `rust-analyzer.showSyntaxTree` is enabled in settings, `Rust Syntax Tree: Focus on Rust Syntax Tree View` shows the syntax tree of the current file. + + You can click on nodes in the rust editor to go to the corresponding syntax node. + + You can click on `Reveal Syntax Element` next to a syntax node to go to the corresponding rust code and highlight the proper text range. If you trigger Go to Definition in the inspected Rust source file, - the syntax tree read-only editor should scroll to and select the + the syntax tree view should scroll to and select the appropriate syntax node token. -  + You can click on `Copy` next to a syntax node to copy a text representation of the node. + +  ## Profiling diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md index 21ac3a5a269..a632fc6f5fb 100644 --- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md +++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md @@ -1,5 +1,5 @@ <!--- -lsp/ext.rs hash: 6dd762ae19630ec0 +lsp/ext.rs hash: 2d8604825c458288 If you need to change the above hash to make the test pass, please check if you need to adjust this doc as well and ping this issue: @@ -710,6 +710,23 @@ interface SyntaxTreeParams { Returns textual representation of a parse tree for the file/selected region. Primarily for debugging, but very useful for all people working on rust-analyzer itself. +## View Syntax Tree + +**Method:** `rust-analyzer/viewSyntaxTree` + +**Request:** + +```typescript +interface ViewSyntaxTreeParams { + textDocument: TextDocumentIdentifier, +} +``` + +**Response:** `string` + +Returns json representation of the file's syntax tree. +Used to create a treeView for debugging and working on rust-analyzer itself. + ## View Hir **Method:** `rust-analyzer/viewHir` diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc index 5b86766aa8e..bd091db58d3 100644 --- a/src/tools/rust-analyzer/docs/user/generated_config.adoc +++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc @@ -94,10 +94,10 @@ avoid checking unnecessary things. -- Default: ---- -{ - "miri": null, - "debug_assertions": null -} +[ + "debug_assertions", + "miri" +] ---- List of cfg options to enable with the given values. @@ -716,6 +716,11 @@ Whether to show generic type parameter name inlay hints. -- Whether to show implicit drop hints. -- +[[rust-analyzer.inlayHints.implicitSizedBoundHints.enable]]rust-analyzer.inlayHints.implicitSizedBoundHints.enable (default: `false`):: ++ +-- +Whether to show inlay hints for the implied type parameter `Sized` bound. +-- [[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`):: + -- @@ -1046,10 +1051,25 @@ Show full signature of the callable. Only shows parameters if disabled. -- Show documentation. -- -[[rust-analyzer.typing.excludeChars]]rust-analyzer.typing.excludeChars (default: `"|<"`):: +[[rust-analyzer.typing.triggerChars]]rust-analyzer.typing.triggerChars (default: `"=."`):: ++ +-- +Specify the characters allowed to invoke special on typing triggers. +- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression +- typing `=` between two expressions adds `;` when in statement position +- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position +- typing `.` in a chain method call auto-indents +- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression +- typing `{` in a use item adds a closing `}` in the right place +- typing `>` to complete a return type `->` will insert a whitespace after it +- typing `<` in a path or type position inserts a closing `>` after the path or type. +-- +[[rust-analyzer.vfs.extraIncludes]]rust-analyzer.vfs.extraIncludes (default: `[]`):: + -- -Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`. +Additional paths to include in the VFS. Generally for code that is +generated or otherwise managed by a build system outside of Cargo, +though Cargo might be the eventual consumer. -- [[rust-analyzer.workspace.discoverConfig]]rust-analyzer.workspace.discoverConfig (default: `null`):: + diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json index 80246bf3fea..8b066377f2b 100644 --- a/src/tools/rust-analyzer/editors/code/package.json +++ b/src/tools/rust-analyzer/editors/code/package.json @@ -109,11 +109,6 @@ ], "commands": [ { - "command": "rust-analyzer.syntaxTree", - "title": "Show Syntax Tree", - "category": "rust-analyzer (debug command)" - }, - { "command": "rust-analyzer.viewHir", "title": "View Hir", "category": "rust-analyzer (debug command)" @@ -289,6 +284,30 @@ "category": "rust-analyzer" }, { + "command": "rust-analyzer.syntaxTreeReveal", + "title": "Reveal Syntax Element", + "icon": "$(search)", + "category": "rust-analyzer (syntax tree)" + }, + { + "command": "rust-analyzer.syntaxTreeCopy", + "title": "Copy", + "icon": "$(copy)", + "category": "rust-analyzer (syntax tree)" + }, + { + "command": "rust-analyzer.syntaxTreeHideWhitespace", + "title": "Hide Whitespace", + "icon": "$(filter)", + "category": "rust-analyzer (syntax tree)" + }, + { + "command": "rust-analyzer.syntaxTreeShowWhitespace", + "title": "Show Whitespace", + "icon": "$(filter-filled)", + "category": "rust-analyzer (syntax tree)" + }, + { "command": "rust-analyzer.viewMemoryLayout", "title": "View Memory Layout", "category": "rust-analyzer" @@ -345,6 +364,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.showSyntaxTree": { + "markdownDescription": "Whether to show the syntax tree view.", + "default": false, + "type": "boolean" + }, "rust-analyzer.testExplorer": { "markdownDescription": "Whether to show the test explorer.", "default": false, @@ -791,11 +815,14 @@ "properties": { "rust-analyzer.cargo.cfgs": { "markdownDescription": "List of cfg options to enable with the given values.", - "default": { - "miri": null, - "debug_assertions": null - }, - "type": "object" + "default": [ + "debug_assertions", + "miri" + ], + "type": "array", + "items": { + "type": "string" + } } } }, @@ -2081,6 +2108,16 @@ { "title": "inlayHints", "properties": { + "rust-analyzer.inlayHints.implicitSizedBoundHints.enable": { + "markdownDescription": "Whether to show inlay hints for the implied type parameter `Sized` bound.", + "default": false, + "type": "boolean" + } + } + }, + { + "title": "inlayHints", + "properties": { "rust-analyzer.inlayHints.lifetimeElisionHints.enable": { "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.", "default": "never", @@ -2708,9 +2745,9 @@ { "title": "typing", "properties": { - "rust-analyzer.typing.excludeChars": { - "markdownDescription": "Specify the characters to exclude from triggering typing assists. The default trigger characters are `.`, `=`, `<`, `>`, `{`, and `(`.", - "default": "|<", + "rust-analyzer.typing.triggerChars": { + "markdownDescription": "Specify the characters allowed to invoke special on typing triggers.\n- typing `=` after `let` tries to smartly add `;` if `=` is followed by an existing expression\n- typing `=` between two expressions adds `;` when in statement position\n- typing `=` to turn an assignment into an equality comparison removes `;` when in expression position\n- typing `.` in a chain method call auto-indents\n- typing `{` or `(` in front of an expression inserts a closing `}` or `)` after the expression\n- typing `{` in a use item adds a closing `}` in the right place\n- typing `>` to complete a return type `->` will insert a whitespace after it\n- typing `<` in a path or type position inserts a closing `>` after the path or type.", + "default": "=.", "type": [ "null", "string" @@ -2719,6 +2756,19 @@ } }, { + "title": "vfs", + "properties": { + "rust-analyzer.vfs.extraIncludes": { + "markdownDescription": "Additional paths to include in the VFS. Generally for code that is\ngenerated or otherwise managed by a build system outside of Cargo,\nthough Cargo might be the eventual consumer.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { "title": "workspace", "properties": { "rust-analyzer.workspace.discoverConfig": { @@ -2928,17 +2978,6 @@ "pattern": "$rustc" } ], - "colors": [ - { - "id": "rust_analyzer.syntaxTreeBorder", - "description": "Color of the border displayed in the Rust source code for the selected syntax node (see \"Show Syntax Tree\" command)", - "defaults": { - "dark": "#ffffff", - "light": "#b700ff", - "highContrast": "#b700ff" - } - } - ], "semanticTokenTypes": [ { "id": "angle", @@ -3259,10 +3298,6 @@ "menus": { "commandPalette": [ { - "command": "rust-analyzer.syntaxTree", - "when": "inRustProject" - }, - { "command": "rust-analyzer.viewHir", "when": "inRustProject" }, @@ -3344,6 +3379,22 @@ }, { "command": "rust-analyzer.openWalkthrough" + }, + { + "command": "rust-analyzer.syntaxTreeReveal", + "when": "false" + }, + { + "command": "rust-analyzer.syntaxTreeCopy", + "when": "false" + }, + { + "command": "rust-analyzer.syntaxTreeHideWhitespace", + "when": "false" + }, + { + "command": "rust-analyzer.syntaxTreeShowWhitespace", + "when": "false" } ], "editor/context": [ @@ -3357,6 +3408,30 @@ "when": "inRustProject && editorTextFocus && editorLangId == rust", "group": "navigation@1001" } + ], + "view/title": [ + { + "command": "rust-analyzer.syntaxTreeHideWhitespace", + "group": "navigation", + "when": "view == rustSyntaxTree && !rustSyntaxTree.hideWhitespace" + }, + { + "command": "rust-analyzer.syntaxTreeShowWhitespace", + "group": "navigation", + "when": "view == rustSyntaxTree && rustSyntaxTree.hideWhitespace" + } + ], + "view/item/context": [ + { + "command": "rust-analyzer.syntaxTreeCopy", + "group": "inline", + "when": "view == rustSyntaxTree" + }, + { + "command": "rust-analyzer.syntaxTreeReveal", + "group": "inline", + "when": "view == rustSyntaxTree" + } ] }, "views": { @@ -3366,6 +3441,22 @@ "name": "Rust Dependencies", "when": "inRustProject && config.rust-analyzer.showDependenciesExplorer" } + ], + "rustSyntaxTreeContainer": [ + { + "id": "rustSyntaxTree", + "name": "Rust Syntax Tree", + "when": "inRustProject && config.rust-analyzer.showSyntaxTree" + } + ] + }, + "viewsContainers": { + "activitybar": [ + { + "id": "rustSyntaxTreeContainer", + "title": "Rust Syntax Tree", + "icon": "$(list-tree)" + } ] }, "jsonValidation": [ diff --git a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts b/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts deleted file mode 100644 index 35b705c477e..00000000000 --- a/src/tools/rust-analyzer/editors/code/src/ast_inspector.ts +++ /dev/null @@ -1,216 +0,0 @@ -import * as vscode from "vscode"; - -import type { Ctx, Disposable } from "./ctx"; -import { type RustEditor, isRustEditor, unwrapUndefinable } from "./util"; - -// FIXME: consider implementing this via the Tree View API? -// https://code.visualstudio.com/api/extension-guides/tree-view -export class AstInspector implements vscode.HoverProvider, vscode.DefinitionProvider, Disposable { - private readonly astDecorationType = vscode.window.createTextEditorDecorationType({ - borderColor: new vscode.ThemeColor("rust_analyzer.syntaxTreeBorder"), - borderStyle: "solid", - borderWidth: "2px", - }); - private rustEditor: undefined | RustEditor; - - // Lazy rust token range -> syntax tree file range. - private readonly rust2Ast = new Lazy(() => { - const astEditor = this.findAstTextEditor(); - if (!this.rustEditor || !astEditor) return undefined; - - const buf: [vscode.Range, vscode.Range][] = []; - for (let i = 0; i < astEditor.document.lineCount; ++i) { - const astLine = astEditor.document.lineAt(i); - - // Heuristically look for nodes with quoted text (which are token nodes) - const isTokenNode = astLine.text.lastIndexOf('"') >= 0; - if (!isTokenNode) continue; - - const rustRange = this.parseRustTextRange(this.rustEditor.document, astLine.text); - if (!rustRange) continue; - - buf.push([rustRange, this.findAstNodeRange(astLine)]); - } - return buf; - }); - - constructor(ctx: Ctx) { - ctx.pushExtCleanup( - vscode.languages.registerHoverProvider({ scheme: "rust-analyzer" }, this), - ); - ctx.pushExtCleanup(vscode.languages.registerDefinitionProvider({ language: "rust" }, this)); - vscode.workspace.onDidCloseTextDocument( - this.onDidCloseTextDocument, - this, - ctx.subscriptions, - ); - vscode.workspace.onDidChangeTextDocument( - this.onDidChangeTextDocument, - this, - ctx.subscriptions, - ); - vscode.window.onDidChangeVisibleTextEditors( - this.onDidChangeVisibleTextEditors, - this, - ctx.subscriptions, - ); - } - dispose() { - this.setRustEditor(undefined); - } - - private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if ( - this.rustEditor && - event.document.uri.toString() === this.rustEditor.document.uri.toString() - ) { - this.rust2Ast.reset(); - } - } - - private onDidCloseTextDocument(doc: vscode.TextDocument) { - if (this.rustEditor && doc.uri.toString() === this.rustEditor.document.uri.toString()) { - this.setRustEditor(undefined); - } - } - - private onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]) { - if (!this.findAstTextEditor()) { - this.setRustEditor(undefined); - return; - } - this.setRustEditor(editors.find(isRustEditor)); - } - - private findAstTextEditor(): undefined | vscode.TextEditor { - return vscode.window.visibleTextEditors.find( - (it) => it.document.uri.scheme === "rust-analyzer", - ); - } - - private setRustEditor(newRustEditor: undefined | RustEditor) { - if (this.rustEditor && this.rustEditor !== newRustEditor) { - this.rustEditor.setDecorations(this.astDecorationType, []); - this.rust2Ast.reset(); - } - this.rustEditor = newRustEditor; - } - - // additional positional params are omitted - provideDefinition( - doc: vscode.TextDocument, - pos: vscode.Position, - ): vscode.ProviderResult<vscode.DefinitionLink[]> { - if (!this.rustEditor || doc.uri.toString() !== this.rustEditor.document.uri.toString()) { - return; - } - - const astEditor = this.findAstTextEditor(); - if (!astEditor) return; - - const rust2AstRanges = this.rust2Ast - .get() - ?.find(([rustRange, _]) => rustRange.contains(pos)); - if (!rust2AstRanges) return; - - const [rustFileRange, astFileRange] = rust2AstRanges; - - astEditor.revealRange(astFileRange); - astEditor.selection = new vscode.Selection(astFileRange.start, astFileRange.end); - - return [ - { - targetRange: astFileRange, - targetUri: astEditor.document.uri, - originSelectionRange: rustFileRange, - targetSelectionRange: astFileRange, - }, - ]; - } - - // additional positional params are omitted - provideHover( - doc: vscode.TextDocument, - hoverPosition: vscode.Position, - ): vscode.ProviderResult<vscode.Hover> { - if (!this.rustEditor) return; - - const astFileLine = doc.lineAt(hoverPosition.line); - - const rustFileRange = this.parseRustTextRange(this.rustEditor.document, astFileLine.text); - if (!rustFileRange) return; - - this.rustEditor.setDecorations(this.astDecorationType, [rustFileRange]); - this.rustEditor.revealRange(rustFileRange); - - const rustSourceCode = this.rustEditor.document.getText(rustFileRange); - const astFileRange = this.findAstNodeRange(astFileLine); - - return new vscode.Hover(["```rust\n" + rustSourceCode + "\n```"], astFileRange); - } - - private findAstNodeRange(astLine: vscode.TextLine): vscode.Range { - const lineOffset = astLine.range.start; - const begin = lineOffset.translate(undefined, astLine.firstNonWhitespaceCharacterIndex); - const end = lineOffset.translate(undefined, astLine.text.trimEnd().length); - return new vscode.Range(begin, end); - } - - private parseRustTextRange( - doc: vscode.TextDocument, - astLine: string, - ): undefined | vscode.Range { - const parsedRange = /(\d+)\.\.(\d+)/.exec(astLine); - if (!parsedRange) return; - - const [begin, end] = parsedRange.slice(1).map((off) => this.positionAt(doc, +off)); - const actualBegin = unwrapUndefinable(begin); - const actualEnd = unwrapUndefinable(end); - return new vscode.Range(actualBegin, actualEnd); - } - - // Memoize the last value, otherwise the CPU is at 100% single core - // with quadratic lookups when we build rust2Ast cache - cache?: { doc: vscode.TextDocument; offset: number; line: number }; - - positionAt(doc: vscode.TextDocument, targetOffset: number): vscode.Position { - if (doc.eol === vscode.EndOfLine.LF) { - return doc.positionAt(targetOffset); - } - - // Dirty workaround for crlf line endings - // We are still in this prehistoric era of carriage returns here... - - let line = 0; - let offset = 0; - - const cache = this.cache; - if (cache?.doc === doc && cache.offset <= targetOffset) { - ({ line, offset } = cache); - } - - while (true) { - const lineLenWithLf = doc.lineAt(line).text.length + 1; - if (offset + lineLenWithLf > targetOffset) { - this.cache = { doc, offset, line }; - return doc.positionAt(targetOffset + line); - } - offset += lineLenWithLf; - line += 1; - } - } -} - -class Lazy<T> { - val: undefined | T; - - constructor(private readonly compute: () => undefined | T) {} - - get() { - return this.val ?? (this.val = this.compute()); - } - - reset() { - this.val = undefined; - } -} diff --git a/src/tools/rust-analyzer/editors/code/src/commands.ts b/src/tools/rust-analyzer/editors/code/src/commands.ts index 73e39c900e7..b3aa04af7ed 100644 --- a/src/tools/rust-analyzer/editors/code/src/commands.ts +++ b/src/tools/rust-analyzer/editors/code/src/commands.ts @@ -15,7 +15,6 @@ import { createTaskFromRunnable, createCargoArgs, } from "./run"; -import { AstInspector } from "./ast_inspector"; import { isRustDocument, isCargoRunnableArgs, @@ -31,8 +30,8 @@ import type { LanguageClient } from "vscode-languageclient/node"; import { HOVER_REFERENCE_COMMAND } from "./client"; import type { DependencyId } from "./dependencies_provider"; import { log } from "./util"; +import type { SyntaxElement } from "./syntax_tree_provider"; -export * from "./ast_inspector"; export * from "./run"; export function analyzerStatus(ctx: CtxInit): Cmd { @@ -288,13 +287,13 @@ export function openCargoToml(ctx: CtxInit): Cmd { export function revealDependency(ctx: CtxInit): Cmd { return async (editor: RustEditor) => { - if (!ctx.dependencies?.isInitialized()) { + if (!ctx.dependenciesProvider?.isInitialized()) { return; } const documentPath = editor.document.uri.fsPath; - const dep = ctx.dependencies?.getDependency(documentPath); + const dep = ctx.dependenciesProvider?.getDependency(documentPath); if (dep) { - await ctx.treeView?.reveal(dep, { select: true, expand: true }); + await ctx.dependencyTreeView?.reveal(dep, { select: true, expand: true }); } else { await revealParentChain(editor.document, ctx); } @@ -340,10 +339,10 @@ async function revealParentChain(document: RustDocument, ctx: CtxInit) { // a open file referencing the old version return; } - } while (!ctx.dependencies?.contains(documentPath)); + } while (!ctx.dependenciesProvider?.contains(documentPath)); parentChain.reverse(); for (const idx in parentChain) { - const treeView = ctx.treeView; + const treeView = ctx.dependencyTreeView; if (!treeView) { continue; } @@ -357,6 +356,77 @@ export async function execRevealDependency(e: RustEditor): Promise<void> { await vscode.commands.executeCommand("rust-analyzer.revealDependency", e); } +export function syntaxTreeReveal(): Cmd { + return async (element: SyntaxElement) => { + const activeEditor = vscode.window.activeTextEditor; + + if (activeEditor !== undefined) { + const start = activeEditor.document.positionAt(element.start); + const end = activeEditor.document.positionAt(element.end); + + const newSelection = new vscode.Selection(start, end); + + activeEditor.selection = newSelection; + activeEditor.revealRange(newSelection); + } + }; +} + +function elementToString( + activeDocument: vscode.TextDocument, + element: SyntaxElement, + depth: number = 0, +): string { + let result = " ".repeat(depth); + const start = element.istart ?? element.start; + const end = element.iend ?? element.end; + + result += `${element.kind}@${start}..${end}`; + + if (element.type === "Token") { + const startPosition = activeDocument.positionAt(element.start); + const endPosition = activeDocument.positionAt(element.end); + const text = activeDocument.getText(new vscode.Range(startPosition, endPosition)); + // JSON.stringify quotes and escapes the string for us. + result += ` ${JSON.stringify(text)}\n`; + } else { + result += "\n"; + for (const child of element.children) { + result += elementToString(activeDocument, child, depth + 1); + } + } + + return result; +} + +export function syntaxTreeCopy(): Cmd { + return async (element: SyntaxElement) => { + const activeDocument = vscode.window.activeTextEditor?.document; + if (!activeDocument) { + return; + } + + const result = elementToString(activeDocument, element); + await vscode.env.clipboard.writeText(result); + }; +} + +export function syntaxTreeHideWhitespace(ctx: CtxInit): Cmd { + return async () => { + if (ctx.syntaxTreeProvider !== undefined) { + await ctx.syntaxTreeProvider.toggleWhitespace(); + } + }; +} + +export function syntaxTreeShowWhitespace(ctx: CtxInit): Cmd { + return async () => { + if (ctx.syntaxTreeProvider !== undefined) { + await ctx.syntaxTreeProvider.toggleWhitespace(); + } + }; +} + export function ssr(ctx: CtxInit): Cmd { return async () => { const editor = vscode.window.activeTextEditor; @@ -426,89 +496,6 @@ export function serverVersion(ctx: CtxInit): Cmd { }; } -// Opens the virtual file that will show the syntax tree -// -// The contents of the file come from the `TextDocumentContentProvider` -export function syntaxTree(ctx: CtxInit): Cmd { - const tdcp = new (class implements vscode.TextDocumentContentProvider { - readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast"); - readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>(); - constructor() { - vscode.workspace.onDidChangeTextDocument( - this.onDidChangeTextDocument, - this, - ctx.subscriptions, - ); - vscode.window.onDidChangeActiveTextEditor( - this.onDidChangeActiveTextEditor, - this, - ctx.subscriptions, - ); - } - - private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) { - if (isRustDocument(event.document)) { - // We need to order this after language server updates, but there's no API for that. - // Hence, good old sleep(). - void sleep(10).then(() => this.eventEmitter.fire(this.uri)); - } - } - private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) { - if (editor && isRustEditor(editor)) { - this.eventEmitter.fire(this.uri); - } - } - - async provideTextDocumentContent( - uri: vscode.Uri, - ct: vscode.CancellationToken, - ): Promise<string> { - const rustEditor = ctx.activeRustEditor; - if (!rustEditor) return ""; - const client = ctx.client; - - // When the range based query is enabled we take the range of the selection - const range = - uri.query === "range=true" && !rustEditor.selection.isEmpty - ? client.code2ProtocolConverter.asRange(rustEditor.selection) - : null; - - const params = { textDocument: { uri: rustEditor.document.uri.toString() }, range }; - return client.sendRequest(ra.syntaxTree, params, ct); - } - - get onDidChange(): vscode.Event<vscode.Uri> { - return this.eventEmitter.event; - } - })(); - - ctx.pushExtCleanup(new AstInspector(ctx)); - ctx.pushExtCleanup( - vscode.workspace.registerTextDocumentContentProvider("rust-analyzer-syntax-tree", tdcp), - ); - ctx.pushExtCleanup( - vscode.languages.setLanguageConfiguration("ra_syntax_tree", { - brackets: [["[", ")"]], - }), - ); - - return async () => { - const editor = vscode.window.activeTextEditor; - const rangeEnabled = !!editor && !editor.selection.isEmpty; - - const uri = rangeEnabled ? vscode.Uri.parse(`${tdcp.uri.toString()}?range=true`) : tdcp.uri; - - const document = await vscode.workspace.openTextDocument(uri); - - tdcp.eventEmitter.fire(uri); - - void (await vscode.window.showTextDocument(document, { - viewColumn: vscode.ViewColumn.Two, - preserveFocus: true, - })); - }; -} - function viewHirOrMir(ctx: CtxInit, xir: "hir" | "mir"): Cmd { const viewXir = xir === "hir" ? "viewHir" : "viewMir"; const requestType = xir === "hir" ? ra.viewHir : ra.viewMir; diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts index 720c473c5b4..d1467a4e824 100644 --- a/src/tools/rust-analyzer/editors/code/src/config.ts +++ b/src/tools/rust-analyzer/editors/code/src/config.ts @@ -351,6 +351,10 @@ export class Config { return this.get<boolean>("showDependenciesExplorer"); } + get showSyntaxTree() { + return this.get<boolean>("showSyntaxTree"); + } + get statusBarClickAction() { return this.get<string>("statusBar.clickAction"); } diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts index 37a54abf71f..5550bfa6558 100644 --- a/src/tools/rust-analyzer/editors/code/src/ctx.ts +++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts @@ -19,6 +19,7 @@ import { RustDependenciesProvider, type DependencyId, } from "./dependencies_provider"; +import { SyntaxTreeProvider, type SyntaxElement } from "./syntax_tree_provider"; import { execRevealDependency } from "./commands"; import { PersistentState } from "./persistent_state"; import { bootstrap } from "./bootstrap"; @@ -84,8 +85,12 @@ export class Ctx implements RustAnalyzerExtensionApi { private commandFactories: Record<string, CommandFactory>; private commandDisposables: Disposable[]; private unlinkedFiles: vscode.Uri[]; - private _dependencies: RustDependenciesProvider | undefined; - private _treeView: vscode.TreeView<Dependency | DependencyFile | DependencyId> | undefined; + private _dependenciesProvider: RustDependenciesProvider | undefined; + private _dependencyTreeView: + | vscode.TreeView<Dependency | DependencyFile | DependencyId> + | undefined; + private _syntaxTreeProvider: SyntaxTreeProvider | undefined; + private _syntaxTreeView: vscode.TreeView<SyntaxElement> | undefined; private lastStatus: ServerStatusParams | { health: "stopped" } = { health: "stopped" }; private _serverVersion: string; private statusBarActiveEditorListener: Disposable; @@ -102,12 +107,20 @@ export class Ctx implements RustAnalyzerExtensionApi { return this._client; } - get treeView() { - return this._treeView; + get dependencyTreeView() { + return this._dependencyTreeView; } - get dependencies() { - return this._dependencies; + get dependenciesProvider() { + return this._dependenciesProvider; + } + + get syntaxTreeView() { + return this._syntaxTreeView; + } + + get syntaxTreeProvider() { + return this._syntaxTreeProvider; } constructor( @@ -278,6 +291,9 @@ export class Ctx implements RustAnalyzerExtensionApi { if (this.config.showDependenciesExplorer) { this.prepareTreeDependenciesView(client); } + if (this.config.showSyntaxTree) { + this.prepareSyntaxTreeView(client); + } } private prepareTreeDependenciesView(client: lc.LanguageClient) { @@ -285,13 +301,13 @@ export class Ctx implements RustAnalyzerExtensionApi { ...this, client: client, }; - this._dependencies = new RustDependenciesProvider(ctxInit); - this._treeView = vscode.window.createTreeView("rustDependencies", { - treeDataProvider: this._dependencies, + this._dependenciesProvider = new RustDependenciesProvider(ctxInit); + this._dependencyTreeView = vscode.window.createTreeView("rustDependencies", { + treeDataProvider: this._dependenciesProvider, showCollapseAll: true, }); - this.pushExtCleanup(this._treeView); + this.pushExtCleanup(this._dependencyTreeView); vscode.window.onDidChangeActiveTextEditor(async (e) => { // we should skip documents that belong to the current workspace if (this.shouldRevealDependency(e)) { @@ -303,7 +319,7 @@ export class Ctx implements RustAnalyzerExtensionApi { } }); - this.treeView?.onDidChangeVisibility(async (e) => { + this.dependencyTreeView?.onDidChangeVisibility(async (e) => { if (e.visible) { const activeEditor = vscode.window.activeTextEditor; if (this.shouldRevealDependency(activeEditor)) { @@ -322,10 +338,60 @@ export class Ctx implements RustAnalyzerExtensionApi { e !== undefined && isRustEditor(e) && !isDocumentInWorkspace(e.document) && - (this.treeView?.visible || false) + (this.dependencyTreeView?.visible || false) ); } + private prepareSyntaxTreeView(client: lc.LanguageClient) { + const ctxInit: CtxInit = { + ...this, + client: client, + }; + this._syntaxTreeProvider = new SyntaxTreeProvider(ctxInit); + this._syntaxTreeView = vscode.window.createTreeView("rustSyntaxTree", { + treeDataProvider: this._syntaxTreeProvider, + showCollapseAll: true, + }); + + this.pushExtCleanup(this._syntaxTreeView); + + vscode.window.onDidChangeActiveTextEditor(async () => { + if (this.syntaxTreeView?.visible) { + await this.syntaxTreeProvider?.refresh(); + } + }); + + vscode.workspace.onDidChangeTextDocument(async () => { + if (this.syntaxTreeView?.visible) { + await this.syntaxTreeProvider?.refresh(); + } + }); + + vscode.window.onDidChangeTextEditorSelection(async (e) => { + if (!this.syntaxTreeView?.visible || !isRustEditor(e.textEditor)) { + return; + } + + const selection = e.selections[0]; + if (selection === undefined) { + return; + } + + const start = e.textEditor.document.offsetAt(selection.start); + const end = e.textEditor.document.offsetAt(selection.end); + const result = this.syntaxTreeProvider?.getElementByRange(start, end); + if (result !== undefined) { + await this.syntaxTreeView?.reveal(result); + } + }); + + this._syntaxTreeView.onDidChangeVisibility(async (e) => { + if (e.visible) { + await this.syntaxTreeProvider?.refresh(); + } + }); + } + async restart() { // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed await this.stopAndDispose(); @@ -423,7 +489,8 @@ export class Ctx implements RustAnalyzerExtensionApi { } else { statusBar.command = "rust-analyzer.openLogs"; } - this.dependencies?.refresh(); + this.dependenciesProvider?.refresh(); + void this.syntaxTreeProvider?.refresh(); break; case "warning": statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground"); diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts index d52e314e219..af86d9efd14 100644 --- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts +++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts @@ -48,6 +48,9 @@ export const runFlycheck = new lc.NotificationType<{ export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>( "rust-analyzer/syntaxTree", ); +export const viewSyntaxTree = new lc.RequestType<ViewSyntaxTreeParams, string, void>( + "rust-analyzer/viewSyntaxTree", +); export const viewCrateGraph = new lc.RequestType<ViewCrateGraphParams, string, void>( "rust-analyzer/viewCrateGraph", ); @@ -157,6 +160,7 @@ export type SyntaxTreeParams = { textDocument: lc.TextDocumentIdentifier; range: lc.Range | null; }; +export type ViewSyntaxTreeParams = { textDocument: lc.TextDocumentIdentifier }; export type ViewCrateGraphParams = { full: boolean }; export type ViewItemTreeParams = { textDocument: lc.TextDocumentIdentifier }; diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts index fdf43f66f94..c84b69b66cd 100644 --- a/src/tools/rust-analyzer/editors/code/src/main.ts +++ b/src/tools/rust-analyzer/editors/code/src/main.ts @@ -158,7 +158,6 @@ function createCommands(): Record<string, CommandFactory> { matchingBrace: { enabled: commands.matchingBrace }, joinLines: { enabled: commands.joinLines }, parentModule: { enabled: commands.parentModule }, - syntaxTree: { enabled: commands.syntaxTree }, viewHir: { enabled: commands.viewHir }, viewMir: { enabled: commands.viewMir }, interpretFunction: { enabled: commands.interpretFunction }, @@ -199,6 +198,10 @@ function createCommands(): Record<string, CommandFactory> { rename: { enabled: commands.rename }, openLogs: { enabled: commands.openLogs }, revealDependency: { enabled: commands.revealDependency }, + syntaxTreeReveal: { enabled: commands.syntaxTreeReveal }, + syntaxTreeCopy: { enabled: commands.syntaxTreeCopy }, + syntaxTreeHideWhitespace: { enabled: commands.syntaxTreeHideWhitespace }, + syntaxTreeShowWhitespace: { enabled: commands.syntaxTreeShowWhitespace }, }; } diff --git a/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts b/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts new file mode 100644 index 00000000000..c7e8007e838 --- /dev/null +++ b/src/tools/rust-analyzer/editors/code/src/syntax_tree_provider.ts @@ -0,0 +1,301 @@ +import * as vscode from "vscode"; + +import { isRustEditor, setContextValue } from "./util"; +import type { CtxInit } from "./ctx"; +import * as ra from "./lsp_ext"; + +export class SyntaxTreeProvider implements vscode.TreeDataProvider<SyntaxElement> { + private _onDidChangeTreeData: vscode.EventEmitter<SyntaxElement | undefined | void> = + new vscode.EventEmitter<SyntaxElement | undefined | void>(); + readonly onDidChangeTreeData: vscode.Event<SyntaxElement | undefined | void> = + this._onDidChangeTreeData.event; + ctx: CtxInit; + root: SyntaxNode | undefined; + hideWhitespace: boolean = false; + + constructor(ctx: CtxInit) { + this.ctx = ctx; + } + + getTreeItem(element: SyntaxElement): vscode.TreeItem { + return new SyntaxTreeItem(element); + } + + getChildren(element?: SyntaxElement): vscode.ProviderResult<SyntaxElement[]> { + return this.getRawChildren(element); + } + + getParent(element: SyntaxElement): vscode.ProviderResult<SyntaxElement> { + return element.parent; + } + + resolveTreeItem( + item: SyntaxTreeItem, + element: SyntaxElement, + _token: vscode.CancellationToken, + ): vscode.ProviderResult<SyntaxTreeItem> { + const editor = vscode.window.activeTextEditor; + + if (editor !== undefined) { + const start = editor.document.positionAt(element.start); + const end = editor.document.positionAt(element.end); + const range = new vscode.Range(start, end); + + const text = editor.document.getText(range); + item.tooltip = new vscode.MarkdownString().appendCodeblock(text, "rust"); + } + + return item; + } + + private getRawChildren(element?: SyntaxElement): SyntaxElement[] { + if (element?.type === "Node") { + if (this.hideWhitespace) { + return element.children.filter((e) => e.kind !== "WHITESPACE"); + } + + return element.children; + } + + if (element?.type === "Token") { + return []; + } + + if (element === undefined && this.root !== undefined) { + return [this.root]; + } + + return []; + } + + async refresh(): Promise<void> { + const editor = vscode.window.activeTextEditor; + + if (editor && isRustEditor(editor)) { + const params = { textDocument: { uri: editor.document.uri.toString() }, range: null }; + const fileText = await this.ctx.client.sendRequest(ra.viewSyntaxTree, params); + this.root = JSON.parse(fileText, (_key, value: SyntaxElement) => { + if (value.type === "Node") { + for (const child of value.children) { + child.parent = value; + } + } + + return value; + }); + } else { + this.root = undefined; + } + + this._onDidChangeTreeData.fire(); + } + + getElementByRange(start: number, end: number): SyntaxElement | undefined { + if (this.root === undefined) { + return undefined; + } + + let result: SyntaxElement = this.root; + + if (this.root.start === start && this.root.end === end) { + return result; + } + + let children = this.getRawChildren(this.root); + + outer: while (true) { + for (const child of children) { + if (child.start <= start && child.end >= end) { + result = child; + if (start === end && start === child.end) { + // When the cursor is on the very end of a token, + // we assume the user wants the next token instead. + continue; + } + + if (child.type === "Token") { + return result; + } else { + children = this.getRawChildren(child); + continue outer; + } + } + } + + return result; + } + } + + async toggleWhitespace() { + this.hideWhitespace = !this.hideWhitespace; + this._onDidChangeTreeData.fire(); + await setContextValue("rustSyntaxTree.hideWhitespace", this.hideWhitespace); + } +} + +export type SyntaxNode = { + type: "Node"; + kind: string; + start: number; + end: number; + istart?: number; + iend?: number; + children: SyntaxElement[]; + parent?: SyntaxElement; +}; + +type SyntaxToken = { + type: "Token"; + kind: string; + start: number; + end: number; + istart?: number; + iend?: number; + parent?: SyntaxElement; +}; + +export type SyntaxElement = SyntaxNode | SyntaxToken; + +export class SyntaxTreeItem extends vscode.TreeItem { + constructor(private readonly element: SyntaxElement) { + super(element.kind); + const icon = getIcon(element.kind); + if (element.type === "Node") { + this.contextValue = "syntaxNode"; + this.iconPath = icon ?? new vscode.ThemeIcon("list-tree"); + this.collapsibleState = vscode.TreeItemCollapsibleState.Expanded; + } else { + this.contextValue = "syntaxToken"; + this.iconPath = icon ?? new vscode.ThemeIcon("symbol-string"); + this.collapsibleState = vscode.TreeItemCollapsibleState.None; + } + + if (element.istart !== undefined && element.iend !== undefined) { + this.description = `${this.element.istart}..${this.element.iend}`; + } else { + this.description = `${this.element.start}..${this.element.end}`; + } + } +} + +function getIcon(kind: string): vscode.ThemeIcon | undefined { + const icon = iconTable[kind]; + + if (icon !== undefined) { + return icon; + } + + if (kind.endsWith("_KW")) { + return new vscode.ThemeIcon( + "symbol-keyword", + new vscode.ThemeColor("symbolIcon.keywordForeground"), + ); + } + + if (operators.includes(kind)) { + return new vscode.ThemeIcon( + "symbol-operator", + new vscode.ThemeColor("symbolIcon.operatorForeground"), + ); + } + + return undefined; +} + +const iconTable: Record<string, vscode.ThemeIcon> = { + CALL_EXPR: new vscode.ThemeIcon("call-outgoing"), + COMMENT: new vscode.ThemeIcon("comment"), + ENUM: new vscode.ThemeIcon("symbol-enum", new vscode.ThemeColor("symbolIcon.enumForeground")), + FN: new vscode.ThemeIcon( + "symbol-function", + new vscode.ThemeColor("symbolIcon.functionForeground"), + ), + FLOAT_NUMBER: new vscode.ThemeIcon( + "symbol-number", + new vscode.ThemeColor("symbolIcon.numberForeground"), + ), + INDEX_EXPR: new vscode.ThemeIcon( + "symbol-array", + new vscode.ThemeColor("symbolIcon.arrayForeground"), + ), + INT_NUMBER: new vscode.ThemeIcon( + "symbol-number", + new vscode.ThemeColor("symbolIcon.numberForeground"), + ), + LITERAL: new vscode.ThemeIcon( + "symbol-misc", + new vscode.ThemeColor("symbolIcon.miscForeground"), + ), + MODULE: new vscode.ThemeIcon( + "symbol-module", + new vscode.ThemeColor("symbolIcon.moduleForeground"), + ), + METHOD_CALL_EXPR: new vscode.ThemeIcon("call-outgoing"), + PARAM: new vscode.ThemeIcon( + "symbol-parameter", + new vscode.ThemeColor("symbolIcon.parameterForeground"), + ), + RECORD_FIELD: new vscode.ThemeIcon( + "symbol-field", + new vscode.ThemeColor("symbolIcon.fieldForeground"), + ), + SOURCE_FILE: new vscode.ThemeIcon("file-code"), + STRING: new vscode.ThemeIcon("quote"), + STRUCT: new vscode.ThemeIcon( + "symbol-struct", + new vscode.ThemeColor("symbolIcon.structForeground"), + ), + TRAIT: new vscode.ThemeIcon( + "symbol-interface", + new vscode.ThemeColor("symbolIcon.interfaceForeground"), + ), + TYPE_PARAM: new vscode.ThemeIcon( + "symbol-type-parameter", + new vscode.ThemeColor("symbolIcon.typeParameterForeground"), + ), + VARIANT: new vscode.ThemeIcon( + "symbol-enum-member", + new vscode.ThemeColor("symbolIcon.enumMemberForeground"), + ), + WHITESPACE: new vscode.ThemeIcon("whitespace"), +}; + +const operators = [ + "PLUS", + "PLUSEQ", + "MINUS", + "MINUSEQ", + "STAR", + "STAREQ", + "SLASH", + "SLASHEQ", + "PERCENT", + "PERCENTEQ", + "CARET", + "CARETEQ", + "AMP", + "AMPEQ", + "AMP2", + "PIPE", + "PIPEEQ", + "PIPE2", + "SHL", + "SHLEQ", + "SHR", + "SHREQ", + "EQ", + "EQ2", + "BANG", + "NEQ", + "L_ANGLE", + "LTEQ", + "R_ANGLE", + "GTEQ", + "COLON2", + "THIN_ARROW", + "FAT_ARROW", + "DOT", + "DOT2", + "DOT2EQ", + "AT", +]; diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs index 11f98f50790..074bc43388a 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs @@ -181,15 +181,15 @@ impl Message { Ok(Some(msg)) } - pub fn write(self, w: &mut impl Write) -> io::Result<()> { + pub fn write(&self, w: &mut impl Write) -> io::Result<()> { self._write(w) } - fn _write(self, w: &mut dyn Write) -> io::Result<()> { + fn _write(&self, w: &mut dyn Write) -> io::Result<()> { #[derive(Serialize)] - struct JsonRpc { + struct JsonRpc<'a> { jsonrpc: &'static str, #[serde(flatten)] - msg: Message, + msg: &'a Message, } let text = serde_json::to_string(&JsonRpc { jsonrpc: "2.0", msg: self })?; write_msg_text(w, &text) diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/socket.rs b/src/tools/rust-analyzer/lib/lsp-server/src/socket.rs index 36d728456f7..48400abf229 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/socket.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/socket.rs @@ -15,8 +15,11 @@ pub(crate) fn socket_transport( stream: TcpStream, ) -> (Sender<Message>, Receiver<Message>, IoThreads) { let (reader_receiver, reader) = make_reader(stream.try_clone().unwrap()); - let (writer_sender, writer) = make_write(stream); - let io_threads = make_io_threads(reader, writer); + let (writer_sender, writer, messages_to_drop) = make_write(stream); + let dropper = std::thread::spawn(move || { + messages_to_drop.into_iter().for_each(drop); + }); + let io_threads = make_io_threads(reader, writer, dropper); (writer_sender, reader_receiver, io_threads) } @@ -36,11 +39,21 @@ fn make_reader(stream: TcpStream) -> (Receiver<Message>, thread::JoinHandle<io:: (reader_receiver, reader) } -fn make_write(mut stream: TcpStream) -> (Sender<Message>, thread::JoinHandle<io::Result<()>>) { +fn make_write( + mut stream: TcpStream, +) -> (Sender<Message>, thread::JoinHandle<io::Result<()>>, Receiver<Message>) { let (writer_sender, writer_receiver) = bounded::<Message>(0); + let (drop_sender, drop_receiver) = bounded::<Message>(0); let writer = thread::spawn(move || { - writer_receiver.into_iter().try_for_each(|it| it.write(&mut stream)).unwrap(); + writer_receiver + .into_iter() + .try_for_each(|it| { + let result = it.write(&mut stream); + let _ = drop_sender.send(it); + result + }) + .unwrap(); Ok(()) }); - (writer_sender, writer) + (writer_sender, writer, drop_receiver) } diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs b/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs index 279a6bce080..8344c9f56b5 100644 --- a/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs +++ b/src/tools/rust-analyzer/lib/lsp-server/src/stdio.rs @@ -11,15 +11,24 @@ use crate::Message; /// Creates an LSP connection via stdio. pub(crate) fn stdio_transport() -> (Sender<Message>, Receiver<Message>, IoThreads) { + let (drop_sender, drop_receiver) = bounded::<Message>(0); let (writer_sender, writer_receiver) = bounded::<Message>(0); let writer = thread::Builder::new() .name("LspServerWriter".to_owned()) .spawn(move || { let stdout = stdout(); let mut stdout = stdout.lock(); - writer_receiver.into_iter().try_for_each(|it| it.write(&mut stdout)) + writer_receiver.into_iter().try_for_each(|it| { + let result = it.write(&mut stdout); + let _ = drop_sender.send(it); + result + }) }) .unwrap(); + let dropper = thread::Builder::new() + .name("LspMessageDropper".to_owned()) + .spawn(move || drop_receiver.into_iter().for_each(drop)) + .unwrap(); let (reader_sender, reader_receiver) = bounded::<Message>(0); let reader = thread::Builder::new() .name("LspServerReader".to_owned()) @@ -41,7 +50,7 @@ pub(crate) fn stdio_transport() -> (Sender<Message>, Receiver<Message>, IoThread Ok(()) }) .unwrap(); - let threads = IoThreads { reader, writer }; + let threads = IoThreads { reader, writer, dropper }; (writer_sender, reader_receiver, threads) } @@ -49,13 +58,15 @@ pub(crate) fn stdio_transport() -> (Sender<Message>, Receiver<Message>, IoThread pub(crate) fn make_io_threads( reader: thread::JoinHandle<io::Result<()>>, writer: thread::JoinHandle<io::Result<()>>, + dropper: thread::JoinHandle<()>, ) -> IoThreads { - IoThreads { reader, writer } + IoThreads { reader, writer, dropper } } pub struct IoThreads { reader: thread::JoinHandle<io::Result<()>>, writer: thread::JoinHandle<io::Result<()>>, + dropper: thread::JoinHandle<()>, } impl IoThreads { @@ -64,6 +75,12 @@ impl IoThreads { Ok(r) => r?, Err(err) => std::panic::panic_any(err), } + match self.dropper.join() { + Ok(_) => (), + Err(err) => { + std::panic::panic_any(err); + } + } match self.writer.join() { Ok(r) => r, Err(err) => { diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 517fdfe18ed..2d9a927c638 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -fb546ee09b226bc4dd4b712d35a372d923c4fa54 +9a1d156f38c51441ee51e5a068f1d0caf4bb0f27 diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock index e05b3c33ca3..86d2abcacb7 100644 --- a/src/tools/rustbook/Cargo.lock +++ b/src/tools/rustbook/Cargo.lock @@ -86,11 +86,12 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys", ] @@ -123,9 +124,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "block-buffer" @@ -161,9 +162,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.8" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0cf6e91fde44c773c6ee7ec6bba798504641a8bc2eb7e37a04ffbf4dfaa55a" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "shlex", ] @@ -771,9 +772,9 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "js-sys" -version = "0.3.76" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -834,9 +835,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" [[package]] name = "mac" @@ -951,9 +952,9 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "miniz_oxide" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" dependencies = [ "adler2", ] @@ -1219,7 +1220,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "memchr", "pulldown-cmark-escape 0.10.1", "unicase", @@ -1231,7 +1232,7 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "679341d22c78c6c649893cbd6c3278dcbe9fc4faa62fea3a9296ae2b50c14625" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "memchr", "pulldown-cmark-escape 0.11.0", "unicase", @@ -1243,7 +1244,7 @@ version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "getopts", "memchr", "pulldown-cmark-escape 0.11.0", @@ -1325,7 +1326,7 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", ] [[package]] @@ -1375,7 +1376,7 @@ version = "0.38.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6" dependencies = [ - "bitflags 2.7.0", + "bitflags 2.8.0", "errno", "libc", "linux-raw-sys", @@ -1383,6 +1384,12 @@ dependencies = [ ] [[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1794,20 +1801,21 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", @@ -1819,9 +1827,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1829,9 +1837,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", @@ -1842,9 +1850,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.99" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "winapi" diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 575716eb6dd..6f0fd09b353 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,5 +1,3 @@ -run-make/cat-and-grep-sanity-check/Makefile -run-make/jobserver-error/Makefile run-make/split-debuginfo/Makefile run-make/symbol-mangling-hashed/Makefile run-make/translation/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index d4cbc37f6d2..59e0042e5c9 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -438,6 +438,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "windows-implement", "windows-interface", "windows-result", + "windows-strings", "windows-sys", "windows-targets", "windows_aarch64_gnullvm", diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 54de2ef8314..de3380502bf 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -183,7 +183,6 @@ ui/async-await/issue-67252-unnamed-future.rs ui/async-await/issue-67651.rs ui/async-await/issue-67765-async-diagnostic.rs ui/async-await/issue-68112.rs -ui/async-await/issue-68523-start.rs ui/async-await/issue-68523.rs ui/async-await/issue-69446-fnmut-capture.rs ui/async-await/issue-70594.rs @@ -2395,7 +2394,6 @@ ui/issues/issue-50618.rs ui/issues/issue-5062.rs ui/issues/issue-5067.rs ui/issues/issue-50688.rs -ui/issues/issue-50714-1.rs ui/issues/issue-50714.rs ui/issues/issue-50761.rs ui/issues/issue-50781.rs @@ -2630,7 +2628,6 @@ ui/issues/issue-9259.rs ui/issues/issue-92741.rs ui/issues/issue-9382.rs ui/issues/issue-9446.rs -ui/issues/issue-9575.rs ui/issues/issue-9719.rs ui/issues/issue-9725.rs ui/issues/issue-9737.rs @@ -2645,7 +2642,6 @@ ui/issues/issue-9968.rs ui/issues/issue-99838.rs ui/iterators/issue-28098.rs ui/iterators/issue-58952-filter-type-length.rs -ui/lang-items/issue-19660.rs ui/lang-items/issue-83471.rs ui/lang-items/issue-87573.rs ui/late-bound-lifetimes/issue-36381.rs @@ -3702,7 +3698,6 @@ ui/rfcs/rfc-2005-default-binding-mode/issue-44912-or.rs ui/rfcs/rfc-2008-non-exhaustive/uninhabited/issue-65157-repeated-match-arm.rs ui/rfcs/rfc-2093-infer-outlives/issue-54467.rs ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-main.rs -ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs ui/rfcs/rfc-2396-target_feature-11/issue-108655-inline-always-closure.rs ui/rfcs/rfc-2396-target_feature-11/issue-99876.rs ui/rfcs/rfc-2497-if-let-chains/issue-88498.rs diff --git a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs index 00edf99a30d..ee92d302db3 100644 --- a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs +++ b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs @@ -58,7 +58,7 @@ pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) { let mut expected_revisions = BTreeSet::new(); - let contents = std::fs::read_to_string(test).unwrap(); + let Ok(contents) = std::fs::read_to_string(test) else { continue }; // Collect directives. iter_header(&contents, &mut |HeaderLine { revision, directive, .. }| { diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 401169c838f..63ac447a772 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -17,7 +17,7 @@ use ignore::Walk; const ENTRY_LIMIT: u32 = 901; // FIXME: The following limits should be reduced eventually. -const ISSUES_ENTRY_LIMIT: u32 = 1667; +const ISSUES_ENTRY_LIMIT: u32 = 1664; const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ "rs", // test source files diff --git a/src/tools/wasm-component-ld/Cargo.toml b/src/tools/wasm-component-ld/Cargo.toml index 965e9b01a44..f8ae91f9e6f 100644 --- a/src/tools/wasm-component-ld/Cargo.toml +++ b/src/tools/wasm-component-ld/Cargo.toml @@ -10,4 +10,4 @@ name = "wasm-component-ld" path = "src/main.rs" [dependencies] -wasm-component-ld = "0.5.11" +wasm-component-ld = "0.5.12" diff --git a/tests/codegen-units/item-collection/cross-crate-closures.rs b/tests/codegen-units/item-collection/cross-crate-closures.rs index cb86cf18c0c..75a77cc2671 100644 --- a/tests/codegen-units/item-collection/cross-crate-closures.rs +++ b/tests/codegen-units/item-collection/cross-crate-closures.rs @@ -3,14 +3,14 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no #![deny(dead_code)] -#![feature(start)] +#![no_main] //@ aux-build:cgu_extern_closures.rs extern crate cgu_extern_closures; -//~ MONO_ITEM fn start @@ cross_crate_closures-cgu.0[Internal] -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +//~ MONO_ITEM fn main @@ cross_crate_closures-cgu.0[External] +#[no_mangle] +extern "C" fn main(_: core::ffi::c_int, _: *const *const u8) -> core::ffi::c_int { //~ MONO_ITEM fn cgu_extern_closures::inlined_fn @@ cross_crate_closures-cgu.0[Internal] //~ MONO_ITEM fn cgu_extern_closures::inlined_fn::{closure#0} @@ cross_crate_closures-cgu.0[Internal] let _ = cgu_extern_closures::inlined_fn(1, 2); diff --git a/tests/codegen-units/item-collection/cross-crate-generic-functions.rs b/tests/codegen-units/item-collection/cross-crate-generic-functions.rs index d36f7067b32..4382bfdf8d8 100644 --- a/tests/codegen-units/item-collection/cross-crate-generic-functions.rs +++ b/tests/codegen-units/item-collection/cross-crate-generic-functions.rs @@ -1,14 +1,14 @@ //@ compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] //@ aux-build:cgu_generic_function.rs extern crate cgu_generic_function; //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn cgu_generic_function::bar::<u32> //~ MONO_ITEM fn cgu_generic_function::foo::<u32> let _ = cgu_generic_function::foo(1u32); diff --git a/tests/codegen-units/item-collection/cross-crate-trait-method.rs b/tests/codegen-units/item-collection/cross-crate-trait-method.rs index 99777760315..917354166f5 100644 --- a/tests/codegen-units/item-collection/cross-crate-trait-method.rs +++ b/tests/codegen-units/item-collection/cross-crate-trait-method.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no -Copt-level=0 #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] //@ aux-build:cgu_export_trait_method.rs extern crate cgu_export_trait_method; @@ -9,8 +9,8 @@ extern crate cgu_export_trait_method; use cgu_export_trait_method::Trait; //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { // The object code of these methods is contained in the external crate, so // calling them should *not* introduce codegen items in the current crate. let _: (u32, u32) = Trait::without_default_impl(0); diff --git a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs index d87ad41e70d..e1887b93b93 100644 --- a/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs +++ b/tests/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -3,7 +3,7 @@ //@ compile-flags:-Zinline-in-all-cgus //@ compile-flags:-Zinline-mir=no -#![feature(start)] +#![crate_type = "lib"] //~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDtor> - shim(Some(StructWithDtor)) @@ drop_in_place_intrinsic-cgu.0[Internal] struct StructWithDtor(u32); @@ -14,8 +14,8 @@ impl Drop for StructWithDtor { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn std::ptr::drop_in_place::<[StructWithDtor; 2]> - shim(Some([StructWithDtor; 2])) @@ drop_in_place_intrinsic-cgu.0[Internal] let x = [StructWithDtor(0), StructWithDtor(1)]; diff --git a/tests/codegen-units/item-collection/function-as-argument.rs b/tests/codegen-units/item-collection/function-as-argument.rs index 4be713dc367..146a53bb911 100644 --- a/tests/codegen-units/item-collection/function-as-argument.rs +++ b/tests/codegen-units/item-collection/function-as-argument.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] fn take_fn_once<T1, T2, F: FnOnce(T1, T2)>(f: F, x: T1, y: T2) { (f)(x, y) @@ -14,8 +14,8 @@ fn take_fn_pointer<T1, T2>(f: fn(T1, T2), x: T1, y: T2) { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn take_fn_once::<u32, &str, fn(u32, &str) {function::<u32, &str>}> //~ MONO_ITEM fn function::<u32, &str> //~ MONO_ITEM fn <fn(u32, &str) {function::<u32, &str>} as std::ops::FnOnce<(u32, &str)>>::call_once - shim(fn(u32, &str) {function::<u32, &str>}) diff --git a/tests/codegen-units/item-collection/generic-drop-glue.rs b/tests/codegen-units/item-collection/generic-drop-glue.rs index d861d269fae..6ecf98a032f 100644 --- a/tests/codegen-units/item-collection/generic-drop-glue.rs +++ b/tests/codegen-units/item-collection/generic-drop-glue.rs @@ -3,7 +3,7 @@ //@ compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] struct StructWithDrop<T1, T2> { x: T1, @@ -44,8 +44,8 @@ impl Drop for NonGenericWithDrop { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDrop<i8, char>> - shim(Some(StructWithDrop<i8, char>)) @@ generic_drop_glue-cgu.0[Internal] //~ MONO_ITEM fn <StructWithDrop<i8, char> as std::ops::Drop>::drop let _ = StructWithDrop { x: 0i8, y: 'a' }.x; diff --git a/tests/codegen-units/item-collection/generic-functions.rs b/tests/codegen-units/item-collection/generic-functions.rs index 2d7c70c9c4c..4a890790702 100644 --- a/tests/codegen-units/item-collection/generic-functions.rs +++ b/tests/codegen-units/item-collection/generic-functions.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] fn foo1<T1>(a: T1) -> (T1, u32) { (a, 1) @@ -22,8 +22,8 @@ pub fn lifetime_only<'a>(a: &'a u32) -> &'a u32 { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn foo1::<i32> let _ = foo1(2i32); //~ MONO_ITEM fn foo1::<i64> diff --git a/tests/codegen-units/item-collection/generic-impl.rs b/tests/codegen-units/item-collection/generic-impl.rs index f6e49f6e6df..5a43bd64b2a 100644 --- a/tests/codegen-units/item-collection/generic-impl.rs +++ b/tests/codegen-units/item-collection/generic-impl.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] struct Struct<T> { x: T, @@ -38,8 +38,8 @@ impl<'a> LifeTimeOnly<'a> { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn Struct::<i32>::new //~ MONO_ITEM fn id::<i32> //~ MONO_ITEM fn Struct::<i32>::get::<i16> diff --git a/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs b/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs index 0b7f30187b5..d916fa6a825 100644 --- a/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs +++ b/tests/codegen-units/item-collection/impl-in-non-instantiated-generic.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] trait SomeTrait { fn foo(&self); @@ -19,8 +19,8 @@ pub fn generic_function<T>(x: T) -> (T, i32) { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { 0i64.foo(); 0 diff --git a/tests/codegen-units/item-collection/instantiation-through-vtable.rs b/tests/codegen-units/item-collection/instantiation-through-vtable.rs index 59dd4311a03..9087fc6410a 100644 --- a/tests/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/tests/codegen-units/item-collection/instantiation-through-vtable.rs @@ -2,7 +2,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-in-all-cgus -Zmir-opt-level=0 #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] trait Trait { fn foo(&self) -> u32; @@ -21,8 +21,8 @@ impl<T> Trait for Struct<T> { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { let s1 = Struct { _a: 0u32 }; //~ MONO_ITEM fn std::ptr::drop_in_place::<Struct<u32>> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal] diff --git a/tests/codegen-units/item-collection/items-within-generic-items.rs b/tests/codegen-units/item-collection/items-within-generic-items.rs index 7798d2b46d2..56d21d5895c 100644 --- a/tests/codegen-units/item-collection/items-within-generic-items.rs +++ b/tests/codegen-units/item-collection/items-within-generic-items.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Copt-level=0 #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] fn generic_fn<T>(a: T) -> (T, i32) { //~ MONO_ITEM fn generic_fn::nested_fn @@ -22,8 +22,8 @@ fn generic_fn<T>(a: T) -> (T, i32) { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn generic_fn::<i64> let _ = generic_fn(0i64); //~ MONO_ITEM fn generic_fn::<u16> diff --git a/tests/codegen-units/item-collection/non-generic-closures.rs b/tests/codegen-units/item-collection/non-generic-closures.rs index 8847a249b1e..4dbc0b62b97 100644 --- a/tests/codegen-units/item-collection/non-generic-closures.rs +++ b/tests/codegen-units/item-collection/non-generic-closures.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] //~ MONO_ITEM fn temporary @@ non_generic_closures-cgu.0[Internal] fn temporary() { @@ -40,9 +40,9 @@ fn assigned_to_variable_executed_directly() { f(4); } -//~ MONO_ITEM fn start @@ non_generic_closures-cgu.0[Internal] -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +//~ MONO_ITEM fn start @@ non_generic_closures-cgu.0[External] +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { temporary(); assigned_to_variable_but_not_executed(); assigned_to_variable_executed_directly(); diff --git a/tests/codegen-units/item-collection/non-generic-drop-glue.rs b/tests/codegen-units/item-collection/non-generic-drop-glue.rs index f7bb2f3f2f4..c4d7942ba1e 100644 --- a/tests/codegen-units/item-collection/non-generic-drop-glue.rs +++ b/tests/codegen-units/item-collection/non-generic-drop-glue.rs @@ -3,7 +3,7 @@ //@ compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] //~ MONO_ITEM fn std::ptr::drop_in_place::<StructWithDrop> - shim(Some(StructWithDrop)) @@ non_generic_drop_glue-cgu.0[Internal] struct StructWithDrop { @@ -34,8 +34,8 @@ enum EnumNoDrop { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { let _ = StructWithDrop { x: 0 }.x; let _ = StructNoDrop { x: 0 }.x; let _ = match EnumWithDrop::A(0) { diff --git a/tests/codegen-units/item-collection/non-generic-functions.rs b/tests/codegen-units/item-collection/non-generic-functions.rs index d4d7d221827..4b86b1088f1 100644 --- a/tests/codegen-units/item-collection/non-generic-functions.rs +++ b/tests/codegen-units/item-collection/non-generic-functions.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] //~ MONO_ITEM fn foo fn foo() { @@ -62,8 +62,8 @@ impl Struct { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { foo(); bar(); Struct::foo(); diff --git a/tests/codegen-units/item-collection/static-init.rs b/tests/codegen-units/item-collection/static-init.rs index 44b80ef73a4..5e3d06790a2 100644 --- a/tests/codegen-units/item-collection/static-init.rs +++ b/tests/codegen-units/item-collection/static-init.rs @@ -1,16 +1,16 @@ //@ compile-flags:-Zprint-mono-items=eager -#![feature(start)] +#![crate_type = "lib"] -pub static FN: fn() = foo::<i32>; +static FN: fn() = foo::<i32>; -pub fn foo<T>() {} +fn foo<T>() {} //~ MONO_ITEM fn foo::<i32> //~ MONO_ITEM static FN //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { 0 } diff --git a/tests/codegen-units/item-collection/statics-and-consts.rs b/tests/codegen-units/item-collection/statics-and-consts.rs index 1e3782f0c6e..54297a40851 100644 --- a/tests/codegen-units/item-collection/statics-and-consts.rs +++ b/tests/codegen-units/item-collection/statics-and-consts.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] static STATIC1: i64 = { const STATIC1_CONST1: i64 = 2; @@ -38,8 +38,8 @@ fn foo() { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { foo(); let _ = STATIC1; diff --git a/tests/codegen-units/item-collection/trait-implementations.rs b/tests/codegen-units/item-collection/trait-implementations.rs index e4c444499e0..3b67d4f22bd 100644 --- a/tests/codegen-units/item-collection/trait-implementations.rs +++ b/tests/codegen-units/item-collection/trait-implementations.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] pub trait SomeTrait { fn foo(&self); @@ -42,8 +42,8 @@ impl<T> SomeGenericTrait<T> for f32 { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn <i32 as SomeTrait>::bar::<char> 0i32.bar('x'); diff --git a/tests/codegen-units/item-collection/trait-method-as-argument.rs b/tests/codegen-units/item-collection/trait-method-as-argument.rs index 10cf2a0e967..d425ea19988 100644 --- a/tests/codegen-units/item-collection/trait-method-as-argument.rs +++ b/tests/codegen-units/item-collection/trait-method-as-argument.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] trait Trait: Sized { fn foo(self) -> Self { @@ -30,8 +30,8 @@ fn take_foo_mut<T, F: FnMut(T) -> T>(mut f: F, arg: T) -> T { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn take_foo_once::<u32, fn(u32) -> u32 {<u32 as Trait>::foo}> //~ MONO_ITEM fn <u32 as Trait>::foo //~ MONO_ITEM fn <fn(u32) -> u32 {<u32 as Trait>::foo} as std::ops::FnOnce<(u32,)>>::call_once - shim(fn(u32) -> u32 {<u32 as Trait>::foo}) diff --git a/tests/codegen-units/item-collection/trait-method-default-impl.rs b/tests/codegen-units/item-collection/trait-method-default-impl.rs index fd73786a402..cd0a4b89031 100644 --- a/tests/codegen-units/item-collection/trait-method-default-impl.rs +++ b/tests/codegen-units/item-collection/trait-method-default-impl.rs @@ -1,7 +1,7 @@ //@ compile-flags:-Zprint-mono-items=eager -Zinline-mir=no #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] trait SomeTrait { fn foo(&self) {} @@ -39,8 +39,8 @@ impl<T1> SomeGenericTrait<T1> for u32 { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn <i8 as SomeTrait>::bar::<char> let _ = 1i8.bar('c'); diff --git a/tests/codegen-units/item-collection/transitive-drop-glue.rs b/tests/codegen-units/item-collection/transitive-drop-glue.rs index 7c879dee1a1..18954fab86f 100644 --- a/tests/codegen-units/item-collection/transitive-drop-glue.rs +++ b/tests/codegen-units/item-collection/transitive-drop-glue.rs @@ -3,7 +3,7 @@ //@ compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] //~ MONO_ITEM fn std::ptr::drop_in_place::<Root> - shim(Some(Root)) @@ transitive_drop_glue-cgu.0[Internal] struct Root(#[allow(dead_code)] Intermediate); @@ -26,8 +26,8 @@ impl<T> Drop for LeafGen<T> { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { let _ = Root(Intermediate(Leaf)); //~ MONO_ITEM fn std::ptr::drop_in_place::<RootGen<u32>> - shim(Some(RootGen<u32>)) @@ transitive_drop_glue-cgu.0[Internal] diff --git a/tests/codegen-units/item-collection/tuple-drop-glue.rs b/tests/codegen-units/item-collection/tuple-drop-glue.rs index 9d8b0cdd384..2e70d0151eb 100644 --- a/tests/codegen-units/item-collection/tuple-drop-glue.rs +++ b/tests/codegen-units/item-collection/tuple-drop-glue.rs @@ -3,7 +3,7 @@ //@ compile-flags:-Zinline-in-all-cgus #![deny(dead_code)] -#![feature(start)] +#![crate_type = "lib"] //~ MONO_ITEM fn std::ptr::drop_in_place::<Dropped> - shim(Some(Dropped)) @@ tuple_drop_glue-cgu.0[Internal] struct Dropped; @@ -14,8 +14,8 @@ impl Drop for Dropped { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { //~ MONO_ITEM fn std::ptr::drop_in_place::<(u32, Dropped)> - shim(Some((u32, Dropped))) @@ tuple_drop_glue-cgu.0[Internal] let x = (0u32, Dropped); diff --git a/tests/codegen-units/item-collection/unsizing.rs b/tests/codegen-units/item-collection/unsizing.rs index 5ea8b47962a..23e6003dc19 100644 --- a/tests/codegen-units/item-collection/unsizing.rs +++ b/tests/codegen-units/item-collection/unsizing.rs @@ -5,7 +5,7 @@ #![deny(dead_code)] #![feature(coerce_unsized)] #![feature(unsize)] -#![feature(start)] +#![crate_type = "lib"] use std::marker::Unsize; use std::ops::CoerceUnsized; @@ -45,8 +45,8 @@ struct Wrapper<T: ?Sized>(#[allow(dead_code)] *const T); impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Wrapper<U>> for Wrapper<T> {} //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { // simple case let bool_sized = &true; //~ MONO_ITEM fn std::ptr::drop_in_place::<bool> - shim(None) @@ unsizing-cgu.0[Internal] diff --git a/tests/codegen-units/partitioning/methods-are-with-self-type.rs b/tests/codegen-units/partitioning/methods-are-with-self-type.rs index 7c9045e8f1a..94d06829c6c 100644 --- a/tests/codegen-units/partitioning/methods-are-with-self-type.rs +++ b/tests/codegen-units/partitioning/methods-are-with-self-type.rs @@ -46,6 +46,7 @@ mod type2 { } //~ MONO_ITEM fn start @@ methods_are_with_self_type[External] +#[no_mangle] pub fn start() { //~ MONO_ITEM fn mod1::<impl SomeGenericType<u32, u64>>::method @@ methods_are_with_self_type.volatile[External] SomeGenericType(0u32, 0u64).method(); diff --git a/tests/codegen-units/partitioning/vtable-through-const.rs b/tests/codegen-units/partitioning/vtable-through-const.rs index a9186cea9c8..3880bba6f6b 100644 --- a/tests/codegen-units/partitioning/vtable-through-const.rs +++ b/tests/codegen-units/partitioning/vtable-through-const.rs @@ -2,11 +2,13 @@ //@ incremental //@ compile-flags:-Zprint-mono-items=lazy //@ compile-flags:-Zinline-in-all-cgus +// Need to disable optimizations to ensure consistent output across all CI runners. +//@ compile-flags:-Copt-level=0 // This test case makes sure, that references made through constants are // recorded properly in the InliningMap. -#![feature(start)] +#![crate_type = "lib"] mod mod1 { struct NeedsDrop; @@ -51,8 +53,8 @@ mod mod1 { fn do_something_else(&self) {} } - //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something @@ vtable_through_const-mod1.volatile[Internal] - //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something_else @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2>::do_something_else @@ vtable_through_const-mod1.volatile[External] impl Trait2 for NeedsDrop {} pub trait Trait2Gen<T> { @@ -76,9 +78,9 @@ mod mod1 { } //~ MONO_ITEM fn start -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn <mod1::NeedsDrop as std::ops::Drop>::drop @@ vtable_through_const-fallback.cgu[Internal] +#[no_mangle] +pub fn start(_: isize, _: *const *const u8) -> isize { + //~ MONO_ITEM fn <mod1::NeedsDrop as std::ops::Drop>::drop @@ vtable_through_const-fallback.cgu[External] //~ MONO_ITEM fn std::ptr::drop_in_place::<mod1::NeedsDrop> - shim(Some(mod1::NeedsDrop)) @@ vtable_through_const-fallback.cgu[External] // Since Trait1::do_something() is instantiated via its default implementation, @@ -95,8 +97,8 @@ fn start(_: isize, _: *const *const u8) -> isize { // Same as above //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait1Gen<u8>>::do_something @@ vtable_through_const-mod1.volatile[External] //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait1Gen<u8>>::do_something_else @@ vtable_through_const-mod1.volatile[External] - //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something @@ vtable_through_const-mod1.volatile[Internal] - //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something_else @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn <mod1::NeedsDrop as mod1::Trait2Gen<u8>>::do_something_else @@ vtable_through_const-mod1.volatile[External] mod1::TRAIT1_GEN_REF.do_something(0u8); //~ MONO_ITEM fn mod1::id::<char> @@ vtable_through_const-mod1.volatile[External] diff --git a/tests/codegen/gdb_debug_script_load.rs b/tests/codegen/gdb_debug_script_load.rs index 30d518c0bcb..3e92eba10b1 100644 --- a/tests/codegen/gdb_debug_script_load.rs +++ b/tests/codegen/gdb_debug_script_load.rs @@ -4,14 +4,34 @@ //@ ignore-wasm //@ ignore-emscripten -//@ compile-flags: -g -C no-prepopulate-passes +//@ compile-flags: -g -C no-prepopulate-passes -Cpanic=abort -#![feature(start)] +#![feature(lang_items)] +#![no_std] +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[no_mangle] +extern "C" fn rust_eh_personality() { + loop {} +} + +// Needs rustc to generate `main` as that's where the magic load is inserted. +// IOW, we cannot write this test with `#![no_main]`. // CHECK-LABEL: @main // CHECK: load volatile i8, {{.+}} @__rustc_debug_gdb_scripts_section__ -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[lang = "start"] +fn lang_start<T: 'static>( + _main: fn() -> T, + _argc: isize, + _argv: *const *const u8, + _sigpipe: u8, +) -> isize { return 0; } + +fn main() {} diff --git a/tests/codegen/hint/cold_path.rs b/tests/codegen/hint/cold_path.rs new file mode 100644 index 00000000000..dac72073f85 --- /dev/null +++ b/tests/codegen/hint/cold_path.rs @@ -0,0 +1,54 @@ +//@ compile-flags: -O +#![crate_type = "lib"] +#![feature(cold_path)] + +use std::hint::cold_path; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test1(x: bool) { + if x { + path_a(); + } else { + cold_path(); + path_b(); + } + + // CHECK-LABEL: @test1( + // CHECK: br i1 %x, label %bb1, label %bb2, !prof ![[NUM:[0-9]+]] + // CHECK: bb2: + // CHECK: path_b + // CHECK: bb1: + // CHECK: path_a +} + +#[no_mangle] +pub fn test2(x: i32) { + match x > 0 { + true => path_a(), + false => { + cold_path(); + path_b() + } + } + + // CHECK-LABEL: @test2( + // CHECK: br i1 %_2, label %bb2, label %bb1, !prof ![[NUM]] + // CHECK: bb1: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} diff --git a/tests/codegen/hint/likely.rs b/tests/codegen/hint/likely.rs new file mode 100644 index 00000000000..2f589cc99d2 --- /dev/null +++ b/tests/codegen/hint/likely.rs @@ -0,0 +1,81 @@ +//@ compile-flags: -O +#![crate_type = "lib"] +#![feature(likely_unlikely)] + +use std::hint::likely; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test1(x: bool) { + if likely(x) { + path_a(); + } else { + path_b(); + } + + // CHECK-LABEL: @test1( + // CHECK: br i1 %x, label %bb2, label %bb3, !prof ![[NUM:[0-9]+]] + // CHECK: bb3: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test2(x: i32) { + match likely(x > 0) { + true => path_a(), + false => path_b(), + } + + // CHECK-LABEL: @test2( + // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]] + // CHECK: bb3: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test3(x: i8) { + match likely(x < 7) { + true => path_a(), + _ => path_b(), + } + + // CHECK-LABEL: @test3( + // CHECK: br i1 %_2, label %bb2, label %bb3, !prof ![[NUM]] + // CHECK: bb3: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test4(x: u64) { + match likely(x != 33) { + false => path_a(), + _ => path_b(), + } + + // CHECK-LABEL: @test4( + // CHECK: br i1 %0, label %bb3, label %bb2, !prof ![[NUM2:[0-9]+]] + // CHECK: bb3: + // CHECK: path_a + // CHECK: bb2: + // CHECK: path_b +} + +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 2000, i32 1} +// CHECK: ![[NUM2]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen/hint/unlikely.rs b/tests/codegen/hint/unlikely.rs new file mode 100644 index 00000000000..328533f3081 --- /dev/null +++ b/tests/codegen/hint/unlikely.rs @@ -0,0 +1,80 @@ +//@ compile-flags: -O +#![crate_type = "lib"] +#![feature(likely_unlikely)] + +use std::hint::unlikely; + +#[inline(never)] +#[no_mangle] +pub fn path_a() { + println!("path a"); +} + +#[inline(never)] +#[no_mangle] +pub fn path_b() { + println!("path b"); +} + +#[no_mangle] +pub fn test1(x: bool) { + if unlikely(x) { + path_a(); + } else { + path_b(); + } + + // CHECK-LABEL: @test1( + // CHECK: br i1 %x, label %bb2, label %bb4, !prof ![[NUM:[0-9]+]] + // CHECK: bb4: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test2(x: i32) { + match unlikely(x > 0) { + true => path_a(), + false => path_b(), + } + + // CHECK-LABEL: @test2( + // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]] + // CHECK: bb4: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test3(x: i8) { + match unlikely(x < 7) { + true => path_a(), + _ => path_b(), + } + + // CHECK-LABEL: @test3( + // CHECK: br i1 %_2, label %bb2, label %bb4, !prof ![[NUM]] + // CHECK: bb4: + // CHECK: path_b + // CHECK: bb2: + // CHECK: path_a +} + +#[no_mangle] +pub fn test4(x: u64) { + match unlikely(x != 33) { + false => path_a(), + _ => path_b(), + } + + // CHECK-LABEL: @test4( + // CHECK: br i1 %0, label %bb4, label %bb2, !prof ![[NUM2:[0-9]+]] + // CHECK: bb4: + // CHECK: path_a + // CHECK: bb2: + // CHECK: path_b +} + +// CHECK: ![[NUM]] = !{!"branch_weights", {{(!"expected", )?}}i32 1, i32 2000} diff --git a/tests/codegen/intrinsics/transmute-niched.rs b/tests/codegen/intrinsics/transmute-niched.rs index f5b7bd2efea..88119ccb8b2 100644 --- a/tests/codegen/intrinsics/transmute-niched.rs +++ b/tests/codegen/intrinsics/transmute-niched.rs @@ -17,12 +17,13 @@ pub enum SmallEnum { // CHECK-LABEL: @check_to_enum( #[no_mangle] pub unsafe fn check_to_enum(x: i8) -> SmallEnum { - // OPT: %0 = icmp uge i8 %x, 10 - // OPT: call void @llvm.assume(i1 %0) - // OPT: %1 = icmp ule i8 %x, 12 + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, 10 + // OPT: %1 = icmp ule i8 %0, 2 // OPT: call void @llvm.assume(i1 %1) - // DBG-NOT: icmp - // DBG-NOT: assume + // CHECK-NOT: icmp + // CHECK-NOT: assume // CHECK: ret i8 %x transmute(x) @@ -31,12 +32,13 @@ pub unsafe fn check_to_enum(x: i8) -> SmallEnum { // CHECK-LABEL: @check_from_enum( #[no_mangle] pub unsafe fn check_from_enum(x: SmallEnum) -> i8 { - // OPT: %0 = icmp uge i8 %x, 10 - // OPT: call void @llvm.assume(i1 %0) - // OPT: %1 = icmp ule i8 %x, 12 + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, 10 + // OPT: %1 = icmp ule i8 %0, 2 // OPT: call void @llvm.assume(i1 %1) - // DBG-NOT: icmp - // DBG-NOT: assume + // CHECK-NOT: icmp + // CHECK-NOT: assume // CHECK: ret i8 %x transmute(x) @@ -45,12 +47,13 @@ pub unsafe fn check_from_enum(x: SmallEnum) -> i8 { // CHECK-LABEL: @check_to_ordering( #[no_mangle] pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering { - // OPT: %0 = icmp uge i8 %x, -1 - // OPT: %1 = icmp ule i8 %x, 1 - // OPT: %2 = or i1 %0, %1 - // OPT: call void @llvm.assume(i1 %2) - // DBG-NOT: icmp - // DBG-NOT: assume + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, -1 + // OPT: %1 = icmp ule i8 %0, 2 + // OPT: call void @llvm.assume(i1 %1) + // CHECK-NOT: icmp + // CHECK-NOT: assume // CHECK: ret i8 %x transmute(x) @@ -59,12 +62,13 @@ pub unsafe fn check_to_ordering(x: u8) -> std::cmp::Ordering { // CHECK-LABEL: @check_from_ordering( #[no_mangle] pub unsafe fn check_from_ordering(x: std::cmp::Ordering) -> u8 { - // OPT: %0 = icmp uge i8 %x, -1 - // OPT: %1 = icmp ule i8 %x, 1 - // OPT: %2 = or i1 %0, %1 - // OPT: call void @llvm.assume(i1 %2) - // DBG-NOT: icmp - // DBG-NOT: assume + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, -1 + // OPT: %1 = icmp ule i8 %0, 2 + // OPT: call void @llvm.assume(i1 %1) + // CHECK-NOT: icmp + // CHECK-NOT: assume // CHECK: ret i8 %x transmute(x) @@ -98,14 +102,15 @@ pub enum Minus100ToPlus100 { // CHECK-LABEL: @check_enum_from_char( #[no_mangle] pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 { + // CHECK-NOT: icmp + // CHECK-NOT: assume // OPT: %0 = icmp ule i32 %x, 1114111 // OPT: call void @llvm.assume(i1 %0) - // OPT: %1 = icmp uge i32 %x, -100 - // OPT: %2 = icmp ule i32 %x, 100 - // OPT: %3 = or i1 %1, %2 - // OPT: call void @llvm.assume(i1 %3) - // DBG-NOT: icmp - // DBG-NOT: assume + // OPT: %1 = sub i32 %x, -100 + // OPT: %2 = icmp ule i32 %1, 200 + // OPT: call void @llvm.assume(i1 %2) + // CHECK-NOT: icmp + // CHECK-NOT: assume // CHECK: ret i32 %x transmute(x) @@ -114,14 +119,15 @@ pub unsafe fn check_enum_from_char(x: char) -> Minus100ToPlus100 { // CHECK-LABEL: @check_enum_to_char( #[no_mangle] pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char { - // OPT: %0 = icmp uge i32 %x, -100 - // OPT: %1 = icmp ule i32 %x, 100 - // OPT: %2 = or i1 %0, %1 + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i32 %x, -100 + // OPT: %1 = icmp ule i32 %0, 200 + // OPT: call void @llvm.assume(i1 %1) + // OPT: %2 = icmp ule i32 %x, 1114111 // OPT: call void @llvm.assume(i1 %2) - // OPT: %3 = icmp ule i32 %x, 1114111 - // OPT: call void @llvm.assume(i1 %3) - // DBG-NOT: icmp - // DBG-NOT: assume + // CHECK-NOT: icmp + // CHECK-NOT: assume // CHECK: ret i32 %x transmute(x) @@ -130,16 +136,20 @@ pub unsafe fn check_enum_to_char(x: Minus100ToPlus100) -> char { // CHECK-LABEL: @check_swap_pair( #[no_mangle] pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) { + // CHECK-NOT: icmp + // CHECK-NOT: assume // OPT: %0 = icmp ule i32 %x.0, 1114111 // OPT: call void @llvm.assume(i1 %0) - // OPT: %1 = icmp uge i32 %x.0, 1 - // OPT: call void @llvm.assume(i1 %1) - // OPT: %2 = icmp uge i32 %x.1, 1 + // OPT: %1 = sub i32 %x.0, 1 + // OPT: %2 = icmp ule i32 %1, -2 // OPT: call void @llvm.assume(i1 %2) - // OPT: %3 = icmp ule i32 %x.1, 1114111 - // OPT: call void @llvm.assume(i1 %3) - // DBG-NOT: icmp - // DBG-NOT: assume + // OPT: %3 = sub i32 %x.1, 1 + // OPT: %4 = icmp ule i32 %3, -2 + // OPT: call void @llvm.assume(i1 %4) + // OPT: %5 = icmp ule i32 %x.1, 1114111 + // OPT: call void @llvm.assume(i1 %5) + // CHECK-NOT: icmp + // CHECK-NOT: assume // CHECK: %[[P1:.+]] = insertvalue { i32, i32 } poison, i32 %x.0, 0 // CHECK: %[[P2:.+]] = insertvalue { i32, i32 } %[[P1]], i32 %x.1, 1 // CHECK: ret { i32, i32 } %[[P2]] @@ -150,14 +160,15 @@ pub unsafe fn check_swap_pair(x: (char, NonZero<u32>)) -> (NonZero<u32>, char) { // CHECK-LABEL: @check_bool_from_ordering( #[no_mangle] pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool { - // OPT: %0 = icmp uge i8 %x, -1 - // OPT: %1 = icmp ule i8 %x, 1 - // OPT: %2 = or i1 %0, %1 + // CHECK-NOT: icmp + // CHECK-NOT: assume + // OPT: %0 = sub i8 %x, -1 + // OPT: %1 = icmp ule i8 %0, 2 + // OPT: call void @llvm.assume(i1 %1) + // OPT: %2 = icmp ule i8 %x, 1 // OPT: call void @llvm.assume(i1 %2) - // OPT: %3 = icmp ule i8 %x, 1 - // OPT: call void @llvm.assume(i1 %3) - // DBG-NOT: icmp - // DBG-NOT: assume + // CHECK-NOT: icmp + // CHECK-NOT: assume // CHECK: %[[R:.+]] = trunc i8 %x to i1 // CHECK: ret i1 %[[R]] @@ -168,14 +179,15 @@ pub unsafe fn check_bool_from_ordering(x: std::cmp::Ordering) -> bool { #[no_mangle] pub unsafe fn check_bool_to_ordering(x: bool) -> std::cmp::Ordering { // CHECK: %_0 = zext i1 %x to i8 + // CHECK-NOT: icmp + // CHECK-NOT: assume // OPT: %0 = icmp ule i8 %_0, 1 // OPT: call void @llvm.assume(i1 %0) - // OPT: %1 = icmp uge i8 %_0, -1 - // OPT: %2 = icmp ule i8 %_0, 1 - // OPT: %3 = or i1 %1, %2 - // OPT: call void @llvm.assume(i1 %3) - // DBG-NOT: icmp - // DBG-NOT: assume + // OPT: %1 = sub i8 %_0, -1 + // OPT: %2 = icmp ule i8 %1, 2 + // OPT: call void @llvm.assume(i1 %2) + // CHECK-NOT: icmp + // CHECK-NOT: assume // CHECK: ret i8 %_0 transmute(x) diff --git a/tests/codegen/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs deleted file mode 100644 index 0bcb311644d..00000000000 --- a/tests/codegen/mainsubprogramstart.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ ignore-apple -//@ ignore-wasi wasi codegens the main symbol differently - -//@ compile-flags: -g -C no-prepopulate-passes - -#![feature(start)] - -// CHECK-LABEL: @main -// CHECK: {{.*}}DISubprogram{{.*}}name: "start",{{.*}}DI{{(SP)?}}FlagMainSubprogram{{.*}} - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { - return 0; -} diff --git a/tests/codegen/overaligned-constant.rs b/tests/codegen/overaligned-constant.rs index 7cd8d19c211..e5540aca387 100644 --- a/tests/codegen/overaligned-constant.rs +++ b/tests/codegen/overaligned-constant.rs @@ -17,8 +17,6 @@ pub fn overaligned_constant() { // CHECK-LABEL: @overaligned_constant // CHECK: [[full:%_.*]] = alloca [32 x i8], align 8 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[full]], ptr align 8 @0, i64 32, i1 false) - // CHECK: %b.0 = load i32, ptr @0, align 4 - // CHECK: %b.1 = load i32, ptr getelementptr inbounds ({{.*}}), align 4 let mut s = S(1); s.0 = 3; diff --git a/tests/codegen/slice-init.rs b/tests/codegen/slice-init.rs index 1c2dd3e8875..b36a5b5de3d 100644 --- a/tests/codegen/slice-init.rs +++ b/tests/codegen/slice-init.rs @@ -2,6 +2,8 @@ #![crate_type = "lib"] +use std::mem::MaybeUninit; + // CHECK-LABEL: @zero_sized_elem #[no_mangle] pub fn zero_sized_elem() { @@ -76,17 +78,64 @@ pub fn u16_init_one_bytes() -> [u16; N] { [const { u16::from_be_bytes([1, 1]) }; N] } -// FIXME: undef bytes can just be initialized with the same value as the -// defined bytes, if the defines bytes are all the same. // CHECK-LABEL: @option_none_init #[no_mangle] pub fn option_none_init() -> [Option<u8>; N] { // CHECK-NOT: select + // CHECK-NOT: br + // CHECK-NOT: switch + // CHECK-NOT: icmp + // CHECK: call void @llvm.memset.p0 + [const { None }; N] +} + +// If there is partial provenance or some bytes are initialized and some are not, +// we can't really do better than initialize bytes or groups of bytes together. +// CHECK-LABEL: @option_maybe_uninit_init +#[no_mangle] +pub fn option_maybe_uninit_init() -> [MaybeUninit<u16>; N] { + // CHECK-NOT: select + // CHECK: br label %repeat_loop_header{{.*}} + // CHECK-NOT: switch + // CHECK: icmp + // CHECK-NOT: call void @llvm.memset.p0 + [const { + let mut val: MaybeUninit<u16> = MaybeUninit::uninit(); + let ptr = val.as_mut_ptr() as *mut u8; + unsafe { + ptr.write(0); + } + val + }; N] +} + +#[repr(packed)] +struct Packed { + start: u8, + ptr: &'static (), + rest: u16, + rest2: u8, +} + +// If there is partial provenance or some bytes are initialized and some are not, +// we can't really do better than initialize bytes or groups of bytes together. +// CHECK-LABEL: @option_maybe_uninit_provenance +#[no_mangle] +pub fn option_maybe_uninit_provenance() -> [MaybeUninit<Packed>; N] { + // CHECK-NOT: select // CHECK: br label %repeat_loop_header{{.*}} // CHECK-NOT: switch // CHECK: icmp // CHECK-NOT: call void @llvm.memset.p0 - [None; N] + [const { + let mut val: MaybeUninit<Packed> = MaybeUninit::uninit(); + unsafe { + let ptr = &raw mut (*val.as_mut_ptr()).ptr; + static HAS_ADDR: () = (); + ptr.write_unaligned(&HAS_ADDR); + } + val + }; N] } // Use an opaque function to prevent rustc from removing useless drops. diff --git a/tests/codegen/transmute-optimized.rs b/tests/codegen/transmute-optimized.rs index 11bd0523788..de54eecf0c0 100644 --- a/tests/codegen/transmute-optimized.rs +++ b/tests/codegen/transmute-optimized.rs @@ -110,3 +110,11 @@ pub fn char_is_negative(c: char) -> bool { let x: i32 = unsafe { std::mem::transmute(c) }; x < 0 } + +// CHECK-LABEL: i1 @transmute_to_char_is_negative(i32 +#[no_mangle] +pub fn transmute_to_char_is_negative(x: i32) -> bool { + // CHECK: ret i1 false + let _c: char = unsafe { std::mem::transmute(x) }; + x < 0 +} diff --git a/tests/crashes/130779.rs b/tests/crashes/130779.rs deleted file mode 100644 index f0fd81fff44..00000000000 --- a/tests/crashes/130779.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #130779 -#![feature(never_patterns)] - -enum E { A } - -fn main() { - match E::A { - ! | - if true => {} - } -} diff --git a/tests/crashes/133063.rs b/tests/crashes/133063.rs deleted file mode 100644 index 132b5486170..00000000000 --- a/tests/crashes/133063.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #133063 - -fn foo(x: !) { - match x { - (! | !) if false => {} - _ => {} - } -} diff --git a/tests/crashes/133117.rs b/tests/crashes/133117.rs deleted file mode 100644 index 751c82626d5..00000000000 --- a/tests/crashes/133117.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ known-bug: #133117 - -fn main() { - match () { - (!|!) if true => {} - (!|!) if true => {} - } -} diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir index 8d9176ef301..a467987e886 100644 --- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir +++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir @@ -7,7 +7,8 @@ fn main() -> () { let mut _5: u32; let mut _6: *mut usize; let _7: usize; - let mut _8: bool; + let mut _8: usize; + let mut _9: bool; scope 1 { debug x => _1; let mut _2: usize; @@ -40,8 +41,9 @@ fn main() -> () { StorageDead(_6); StorageLive(_7); _7 = copy _2; - _8 = Lt(copy _7, const 3_usize); - assert(move _8, "index out of bounds: the length is {} but the index is {}", const 3_usize, copy _7) -> [success: bb2, unwind unreachable]; + _8 = Len(_1); + _9 = Lt(copy _7, copy _8); + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable]; } bb2: { diff --git a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir index e1df0e3e2a3..bd7365543bd 100644 --- a/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir +++ b/tests/mir-opt/array_index_is_temporary.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir @@ -7,7 +7,8 @@ fn main() -> () { let mut _5: u32; let mut _6: *mut usize; let _7: usize; - let mut _8: bool; + let mut _8: usize; + let mut _9: bool; scope 1 { debug x => _1; let mut _2: usize; @@ -40,8 +41,9 @@ fn main() -> () { StorageDead(_6); StorageLive(_7); _7 = copy _2; - _8 = Lt(copy _7, const 3_usize); - assert(move _8, "index out of bounds: the length is {} but the index is {}", const 3_usize, copy _7) -> [success: bb2, unwind continue]; + _8 = Len(_1); + _9 = Lt(copy _7, copy _8); + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue]; } bb2: { diff --git a/tests/mir-opt/building/custom/arrays.arrays.built.after.mir b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir new file mode 100644 index 00000000000..30d11e31e4d --- /dev/null +++ b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir @@ -0,0 +1,14 @@ +// MIR for `arrays` after built + +fn arrays() -> usize { + let mut _0: usize; + let mut _1: [i32; C]; + let mut _2: usize; + + bb0: { + _1 = [const 5_i32; C]; + _2 = Len(_1); + _0 = copy _2; + return; + } +} diff --git a/tests/mir-opt/building/custom/arrays.rs b/tests/mir-opt/building/custom/arrays.rs new file mode 100644 index 00000000000..4bd6f93e113 --- /dev/null +++ b/tests/mir-opt/building/custom/arrays.rs @@ -0,0 +1,22 @@ +// skip-filecheck +#![feature(custom_mir, core_intrinsics)] + +extern crate core; +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() + } + } +} + +fn main() { + assert_eq!(arrays::<20>(), 20); +} diff --git a/tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir deleted file mode 100644 index d28a2031013..00000000000 --- a/tests/mir-opt/building/index_array_and_slice.index_array.built.after.mir +++ /dev/null @@ -1,31 +0,0 @@ -// MIR for `index_array` after built - -fn index_array(_1: &[i32; 7], _2: usize) -> &i32 { - debug array => _1; - debug index => _2; - let mut _0: &i32; - let _3: &i32; - let _4: usize; - let mut _5: bool; - - bb0: { - StorageLive(_3); - StorageLive(_4); - _4 = copy _2; - FakeRead(ForIndex, (*_1)); - _5 = Lt(copy _4, const 7_usize); - assert(move _5, "index out of bounds: the length is {} but the index is {}", const 7_usize, copy _4) -> [success: bb1, unwind: bb2]; - } - - bb1: { - _3 = &(*_1)[_4]; - _0 = &(*_3); - StorageDead(_4); - StorageDead(_3); - return; - } - - bb2 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir deleted file mode 100644 index e9627532c38..00000000000 --- a/tests/mir-opt/building/index_array_and_slice.index_const_generic_array.built.after.mir +++ /dev/null @@ -1,31 +0,0 @@ -// MIR for `index_const_generic_array` after built - -fn index_const_generic_array(_1: &[i32; N], _2: usize) -> &i32 { - debug array => _1; - debug index => _2; - let mut _0: &i32; - let _3: &i32; - let _4: usize; - let mut _5: bool; - - bb0: { - StorageLive(_3); - StorageLive(_4); - _4 = copy _2; - FakeRead(ForIndex, (*_1)); - _5 = Lt(copy _4, const N); - assert(move _5, "index out of bounds: the length is {} but the index is {}", const N, copy _4) -> [success: bb1, unwind: bb2]; - } - - bb1: { - _3 = &(*_1)[_4]; - _0 = &(*_3); - StorageDead(_4); - StorageDead(_3); - return; - } - - bb2 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir deleted file mode 100644 index 00f2b7e07d5..00000000000 --- a/tests/mir-opt/building/index_array_and_slice.index_custom.built.after.mir +++ /dev/null @@ -1,34 +0,0 @@ -// MIR for `index_custom` after built - -fn index_custom(_1: &WithSliceTail, _2: usize) -> &i32 { - debug custom => _1; - debug index => _2; - let mut _0: &i32; - let _3: &i32; - let _4: usize; - let mut _5: *const [i32]; - let mut _6: usize; - let mut _7: bool; - - bb0: { - StorageLive(_3); - StorageLive(_4); - _4 = copy _2; - _5 = &raw const ((*_1).1: [i32]); - _6 = PtrMetadata(move _5); - _7 = Lt(copy _4, copy _6); - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2]; - } - - bb1: { - _3 = &((*_1).1: [i32])[_4]; - _0 = &(*_3); - StorageDead(_4); - StorageDead(_3); - return; - } - - bb2 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir deleted file mode 100644 index cb0b2f600c8..00000000000 --- a/tests/mir-opt/building/index_array_and_slice.index_mut_slice.built.after.mir +++ /dev/null @@ -1,34 +0,0 @@ -// MIR for `index_mut_slice` after built - -fn index_mut_slice(_1: &mut [i32], _2: usize) -> &i32 { - debug slice => _1; - debug index => _2; - let mut _0: &i32; - let _3: &i32; - let _4: usize; - let mut _5: *const [i32]; - let mut _6: usize; - let mut _7: bool; - - bb0: { - StorageLive(_3); - StorageLive(_4); - _4 = copy _2; - _5 = &raw const (*_1); - _6 = PtrMetadata(move _5); - _7 = Lt(copy _4, copy _6); - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb2]; - } - - bb1: { - _3 = &(*_1)[_4]; - _0 = &(*_3); - StorageDead(_4); - StorageDead(_3); - return; - } - - bb2 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir b/tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir deleted file mode 100644 index 0911df59049..00000000000 --- a/tests/mir-opt/building/index_array_and_slice.index_slice.built.after.mir +++ /dev/null @@ -1,32 +0,0 @@ -// MIR for `index_slice` after built - -fn index_slice(_1: &[i32], _2: usize) -> &i32 { - debug slice => _1; - debug index => _2; - let mut _0: &i32; - let _3: &i32; - let _4: usize; - let mut _5: usize; - let mut _6: bool; - - bb0: { - StorageLive(_3); - StorageLive(_4); - _4 = copy _2; - _5 = PtrMetadata(copy _1); - _6 = Lt(copy _4, copy _5); - assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind: bb2]; - } - - bb1: { - _3 = &(*_1)[_4]; - _0 = &(*_3); - StorageDead(_4); - StorageDead(_3); - return; - } - - bb2 (cleanup): { - resume; - } -} diff --git a/tests/mir-opt/building/index_array_and_slice.rs b/tests/mir-opt/building/index_array_and_slice.rs deleted file mode 100644 index 16d0b983132..00000000000 --- a/tests/mir-opt/building/index_array_and_slice.rs +++ /dev/null @@ -1,71 +0,0 @@ -//@ compile-flags: -C opt-level=0 - -// EMIT_MIR index_array_and_slice.index_array.built.after.mir -fn index_array(array: &[i32; 7], index: usize) -> &i32 { - // CHECK: bb0: - // CHECK: [[LT:_.+]] = Lt(copy _2, const 7_usize); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const 7_usize, copy _2) -> [success: bb1, unwind - - // CHECK: bb1: - // CHECK: _0 = &(*_1)[_2]; - &array[index] -} - -// EMIT_MIR index_array_and_slice.index_const_generic_array.built.after.mir -fn index_const_generic_array<const N: usize>(array: &[i32; N], index: usize) -> &i32 { - // CHECK: bb0: - // CHECK: [[LT:_.+]] = Lt(copy _2, const N); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", const N, copy _2) -> [success: bb1, unwind - - // CHECK: bb1: - // CHECK: _0 = &(*_1)[_2]; - &array[index] -} - -// EMIT_MIR index_array_and_slice.index_slice.built.after.mir -fn index_slice(slice: &[i32], index: usize) -> &i32 { - // CHECK: bb0: - // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1); - // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, - - // CHECK: bb1: - // CHECK: _0 = &(*_1)[_2]; - &slice[index] -} - -// EMIT_MIR index_array_and_slice.index_mut_slice.built.after.mir -fn index_mut_slice(slice: &mut [i32], index: usize) -> &i32 { - // While the filecheck here is identical to the above test, the emitted MIR is different. - // This cannot `copy _1` in the *built* MIR, only in the *runtime* MIR. - - // CHECK: bb0: - // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1); - // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, - - // CHECK: bb1: - // CHECK: _0 = &(*_1)[_2]; - &slice[index] -} - -struct WithSliceTail(f64, [i32]); - -// EMIT_MIR index_array_and_slice.index_custom.built.after.mir -fn index_custom(custom: &WithSliceTail, index: usize) -> &i32 { - // CHECK: bb0: - // CHECK: [[PTR:_.+]] = &raw const ((*_1).1: [i32]); - // CHECK: [[LEN:_.+]] = PtrMetadata(move [[PTR]]); - // CHECK: [[LT:_.+]] = Lt(copy _2, copy [[LEN]]); - // CHECK: assert(move [[LT]], "index out of bounds{{.+}}", move [[LEN]], copy _2) -> [success: bb1, - - // CHECK: bb1: - // CHECK: _0 = &((*_1).1: [i32])[_2]; - &custom.1[index] -} - -fn main() { - index_array(&[1, 2, 3, 4, 5, 6, 7], 3); - index_slice(&[1, 2, 3, 4, 5, 6, 7][..], 3); - _ = index_custom; -} diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff index 3a5a8d00991..e754af95ce3 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-abort.diff @@ -6,7 +6,8 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 4_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff index 62d6e6007e5..e15a35c7fe9 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.32bit.panic-unwind.diff @@ -6,7 +6,8 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 4_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff index 3a5a8d00991..e754af95ce3 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-abort.diff @@ -6,7 +6,8 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 4_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff index 62d6e6007e5..e15a35c7fe9 100644 --- a/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/array_index.main.GVN.64bit.panic-unwind.diff @@ -6,7 +6,8 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 4_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff index be42c4d60c8..15d30140367 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-abort.diff @@ -30,22 +30,19 @@ StorageDead(_2); StorageDead(_3); StorageLive(_5); -- StorageLive(_6); -+ nop; + StorageLive(_6); _6 = const 3_usize; -- _7 = PtrMetadata(copy _1); + _7 = Len((*_1)); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _7 = const 3_usize; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable]; ++ _8 = Lt(const 3_usize, copy _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable]; } bb1: { - _5 = copy (*_1)[_6]; -- StorageDead(_6); + _5 = copy (*_1)[3 of 4]; -+ nop; + StorageDead(_6); _0 = const (); StorageDead(_5); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff index b51d0c0845f..dd411d84f9f 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.32bit.panic-unwind.diff @@ -30,22 +30,19 @@ StorageDead(_2); StorageDead(_3); StorageLive(_5); -- StorageLive(_6); -+ nop; + StorageLive(_6); _6 = const 3_usize; -- _7 = PtrMetadata(copy _1); + _7 = Len((*_1)); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _7 = const 3_usize; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue]; ++ _8 = Lt(const 3_usize, copy _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue]; } bb1: { - _5 = copy (*_1)[_6]; -- StorageDead(_6); + _5 = copy (*_1)[3 of 4]; -+ nop; + StorageDead(_6); _0 = const (); StorageDead(_5); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff index be42c4d60c8..15d30140367 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-abort.diff @@ -30,22 +30,19 @@ StorageDead(_2); StorageDead(_3); StorageLive(_5); -- StorageLive(_6); -+ nop; + StorageLive(_6); _6 = const 3_usize; -- _7 = PtrMetadata(copy _1); + _7 = Len((*_1)); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _7 = const 3_usize; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind unreachable]; ++ _8 = Lt(const 3_usize, copy _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind unreachable]; } bb1: { - _5 = copy (*_1)[_6]; -- StorageDead(_6); + _5 = copy (*_1)[3 of 4]; -+ nop; + StorageDead(_6); _0 = const (); StorageDead(_5); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff index b51d0c0845f..dd411d84f9f 100644 --- a/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.GVN.64bit.panic-unwind.diff @@ -30,22 +30,19 @@ StorageDead(_2); StorageDead(_3); StorageLive(_5); -- StorageLive(_6); -+ nop; + StorageLive(_6); _6 = const 3_usize; -- _7 = PtrMetadata(copy _1); + _7 = Len((*_1)); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _7 = const 3_usize; -+ _8 = const false; -+ assert(const false, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 3_usize) -> [success: bb1, unwind continue]; ++ _8 = Lt(const 3_usize, copy _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> [success: bb1, unwind continue]; } bb1: { - _5 = copy (*_1)[_6]; -- StorageDead(_6); + _5 = copy (*_1)[3 of 4]; -+ nop; + StorageDead(_6); _0 = const (); StorageDead(_5); StorageDead(_1); diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff index 3569998b13f..49ea51deed6 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-abort.diff @@ -6,7 +6,8 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 5000_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff index 50b31c9ac13..103bfbcaf64 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.32bit.panic-unwind.diff @@ -6,7 +6,8 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 5000_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff index 3569998b13f..49ea51deed6 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-abort.diff @@ -6,7 +6,8 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 5000_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff index 50b31c9ac13..103bfbcaf64 100644 --- a/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/large_array_index.main.GVN.64bit.panic-unwind.diff @@ -6,7 +6,8 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 5000_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff index a41668b6fa3..f7c1c2da01f 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-abort.diff @@ -7,7 +7,8 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: bool; + let mut _5: usize; + let mut _6: bool; scope 1 { debug x => _1; } @@ -19,9 +20,11 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Lt(copy _4, const 8_usize); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable]; -+ _5 = const true; +- _5 = Len(_3); +- _6 = Lt(copy _4, copy _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff index 2313084b49e..436773c8556 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.32bit.panic-unwind.diff @@ -7,7 +7,8 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: bool; + let mut _5: usize; + let mut _6: bool; scope 1 { debug x => _1; } @@ -19,9 +20,11 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Lt(copy _4, const 8_usize); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue]; -+ _5 = const true; +- _5 = Len(_3); +- _6 = Lt(copy _4, copy _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff index a41668b6fa3..f7c1c2da01f 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-abort.diff @@ -7,7 +7,8 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: bool; + let mut _5: usize; + let mut _6: bool; scope 1 { debug x => _1; } @@ -19,9 +20,11 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Lt(copy _4, const 8_usize); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable]; -+ _5 = const true; +- _5 = Len(_3); +- _6 = Lt(copy _4, copy _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff index 2313084b49e..436773c8556 100644 --- a/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/repeat.main.GVN.64bit.panic-unwind.diff @@ -7,7 +7,8 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: bool; + let mut _5: usize; + let mut _6: bool; scope 1 { debug x => _1; } @@ -19,9 +20,11 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Lt(copy _4, const 8_usize); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue]; -+ _5 = const true; +- _5 = Len(_3); +- _6 = Lt(copy _4, copy _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff index 0798b303929..8a8ea5b7e20 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff @@ -30,12 +30,11 @@ StorageDead(_3); StorageLive(_6); _6 = const 1_usize; -- _7 = PtrMetadata(copy _2); + _7 = Len((*_2)); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _7 = const 3_usize; -+ _8 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; ++ _8 = Lt(const 1_usize, copy _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff index c0b3d4d3219..f0c844884f6 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff @@ -30,12 +30,11 @@ StorageDead(_3); StorageLive(_6); _6 = const 1_usize; -- _7 = PtrMetadata(copy _2); + _7 = Len((*_2)); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _7 = const 3_usize; -+ _8 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; ++ _8 = Lt(const 1_usize, copy _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff index 0798b303929..8a8ea5b7e20 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff @@ -30,12 +30,11 @@ StorageDead(_3); StorageLive(_6); _6 = const 1_usize; -- _7 = PtrMetadata(copy _2); + _7 = Len((*_2)); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; -+ _7 = const 3_usize; -+ _8 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; ++ _8 = Lt(const 1_usize, copy _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind unreachable]; } bb1: { diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff index c0b3d4d3219..f0c844884f6 100644 --- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff @@ -30,12 +30,11 @@ StorageDead(_3); StorageLive(_6); _6 = const 1_usize; -- _7 = PtrMetadata(copy _2); + _7 = Len((*_2)); - _8 = Lt(copy _6, copy _7); - assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; -+ _7 = const 3_usize; -+ _8 = const true; -+ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; ++ _8 = Lt(const 1_usize, copy _7); ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 1_usize) -> [success: bb1, unwind continue]; } bb1: { diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff index 689083dfc1d..6d967257df1 100644 --- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff +++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-abort.diff @@ -18,7 +18,8 @@ let mut _15: !; let mut _17: i32; let _18: usize; - let mut _19: bool; + let mut _19: usize; + let mut _20: bool; scope 1 { debug sum => _1; let _2: [i32; 4]; @@ -91,10 +92,11 @@ StorageLive(_17); - StorageLive(_18); - _18 = copy _16; -- _19 = Lt(copy _18, const 4_usize); -- assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _18) -> [success: bb8, unwind unreachable]; -+ _19 = Lt(copy _16, const 4_usize); -+ assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _16) -> [success: bb8, unwind unreachable]; + _19 = Len(_2); +- _20 = Lt(copy _18, copy _19); +- assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _18) -> [success: bb8, unwind unreachable]; ++ _20 = Lt(copy _16, copy _19); ++ assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _16) -> [success: bb8, unwind unreachable]; } bb7: { diff --git a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff index 7f768a9f834..3580c87c469 100644 --- a/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff +++ b/tests/mir-opt/copy-prop/issue_107511.main.CopyProp.panic-unwind.diff @@ -18,7 +18,8 @@ let mut _15: !; let mut _17: i32; let _18: usize; - let mut _19: bool; + let mut _19: usize; + let mut _20: bool; scope 1 { debug sum => _1; let _2: [i32; 4]; @@ -91,10 +92,11 @@ StorageLive(_17); - StorageLive(_18); - _18 = copy _16; -- _19 = Lt(copy _18, const 4_usize); -- assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _18) -> [success: bb8, unwind continue]; -+ _19 = Lt(copy _16, const 4_usize); -+ assert(move _19, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _16) -> [success: bb8, unwind continue]; + _19 = Len(_2); +- _20 = Lt(copy _18, copy _19); +- assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _18) -> [success: bb8, unwind continue]; ++ _20 = Lt(copy _16, copy _19); ++ assert(move _20, "index out of bounds: the length is {} but the index is {}", move _19, copy _16) -> [success: bb8, unwind continue]; } bb7: { diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff index 0275d7e8a0d..a46daef435f 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -6,7 +6,8 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 4_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff index 490ed4b55a1..1a4e15b45fa 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -6,7 +6,8 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 4_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff index 0275d7e8a0d..a46daef435f 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -6,7 +6,8 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 4_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 4_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff index 490ed4b55a1..1a4e15b45fa 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -6,7 +6,8 @@ let _1: u32; let mut _2: [u32; 4]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 4_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 4_usize, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const 4_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/array_index.rs b/tests/mir-opt/dataflow-const-prop/array_index.rs index 1aa8dcd28f4..e442ef99f79 100644 --- a/tests/mir-opt/dataflow-const-prop/array_index.rs +++ b/tests/mir-opt/dataflow-const-prop/array_index.rs @@ -11,10 +11,9 @@ fn main() { // CHECK: [[array_lit]] = [const 0_u32, const 1_u32, const 2_u32, const 3_u32]; // CHECK-NOT: {{_.*}} = Len( - // CHECK-NOT: {{_.*}} = PtrMetadata( // CHECK-NOT: {{_.*}} = Lt( // CHECK-NOT: assert(move _ - // CHECK: {{_.*}} = const 2_usize; + // CHECK: {{_.*}} = const 4_usize; // CHECK: {{_.*}} = const true; // CHECK: assert(const true // CHECK: [[x]] = copy [[array_lit]][2 of 3]; diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff index f0d59ef5923..b7ff0b671f7 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-abort.diff @@ -6,7 +6,8 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 5000_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff index 959c3e75214..af6e3626142 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.32bit.panic-unwind.diff @@ -6,7 +6,8 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 5000_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff index f0d59ef5923..b7ff0b671f7 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-abort.diff @@ -6,7 +6,8 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 5000_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind unreachable]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; ++ _4 = const 5000_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff index 959c3e75214..af6e3626142 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.main.DataflowConstProp.64bit.panic-unwind.diff @@ -6,7 +6,8 @@ let _1: u8; let mut _2: [u8; 5000]; let _3: usize; - let mut _4: bool; + let mut _4: usize; + let mut _5: bool; scope 1 { debug x => _1; } @@ -17,9 +18,11 @@ _2 = [const 0_u8; 5000]; StorageLive(_3); _3 = const 2_usize; -- _4 = Lt(copy _3, const 5000_usize); -- assert(move _4, "index out of bounds: the length is {} but the index is {}", const 5000_usize, copy _3) -> [success: bb1, unwind continue]; -+ _4 = const true; +- _4 = Len(_2); +- _5 = Lt(copy _3, copy _4); +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; ++ _4 = const 5000_usize; ++ _5 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/large_array_index.rs b/tests/mir-opt/dataflow-const-prop/large_array_index.rs index e490cfde247..e9f2fa2badf 100644 --- a/tests/mir-opt/dataflow-const-prop/large_array_index.rs +++ b/tests/mir-opt/dataflow-const-prop/large_array_index.rs @@ -10,7 +10,7 @@ fn main() { // CHECK: debug x => [[x:_.*]]; // CHECK: [[array_lit:_.*]] = [const 0_u8; 5000]; - // CHECK: {{_.*}} = const 2_usize; + // CHECK: {{_.*}} = const 5000_usize; // CHECK: {{_.*}} = const true; // CHECK: assert(const true // CHECK: [[x]] = copy [[array_lit]][2 of 3]; diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff index 618121ea632..dfa541b1200 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-abort.diff @@ -7,7 +7,8 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: bool; + let mut _5: usize; + let mut _6: bool; scope 1 { debug x => _1; } @@ -19,9 +20,11 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Lt(copy _4, const 8_usize); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable]; -+ _5 = const true; +- _5 = Len(_3); +- _6 = Lt(copy _4, copy _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff index 1788f58432b..9ede3c5f7ac 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.32bit.panic-unwind.diff @@ -7,7 +7,8 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: bool; + let mut _5: usize; + let mut _6: bool; scope 1 { debug x => _1; } @@ -19,9 +20,11 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Lt(copy _4, const 8_usize); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue]; -+ _5 = const true; +- _5 = Len(_3); +- _6 = Lt(copy _4, copy _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff index 618121ea632..dfa541b1200 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-abort.diff @@ -7,7 +7,8 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: bool; + let mut _5: usize; + let mut _6: bool; scope 1 { debug x => _1; } @@ -19,9 +20,11 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Lt(copy _4, const 8_usize); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind unreachable]; -+ _5 = const true; +- _5 = Len(_3); +- _6 = Lt(copy _4, copy _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind unreachable]; ++ _5 = const 8_usize; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff index 1788f58432b..9ede3c5f7ac 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff +++ b/tests/mir-opt/dataflow-const-prop/repeat.main.DataflowConstProp.64bit.panic-unwind.diff @@ -7,7 +7,8 @@ let mut _2: u32; let mut _3: [u32; 8]; let _4: usize; - let mut _5: bool; + let mut _5: usize; + let mut _6: bool; scope 1 { debug x => _1; } @@ -19,9 +20,11 @@ _3 = [const 42_u32; 8]; StorageLive(_4); _4 = const 2_usize; -- _5 = Lt(copy _4, const 8_usize); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", const 8_usize, copy _4) -> [success: bb1, unwind continue]; -+ _5 = const true; +- _5 = Len(_3); +- _6 = Lt(copy _4, copy _5); +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind continue]; ++ _5 = const 8_usize; ++ _6 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/dataflow-const-prop/repeat.rs b/tests/mir-opt/dataflow-const-prop/repeat.rs index 1bc2cb82a60..2067aa3d709 100644 --- a/tests/mir-opt/dataflow-const-prop/repeat.rs +++ b/tests/mir-opt/dataflow-const-prop/repeat.rs @@ -9,9 +9,8 @@ fn main() { // CHECK: [[array_lit:_.*]] = [const 42_u32; 8]; // CHECK-NOT: {{_.*}} = Len( - // CHECK-NOT: {{_.*}} = PtrMetadata( // CHECK-NOT: {{_.*}} = Lt( - // CHECK: {{_.*}} = const 2_usize; + // CHECK: {{_.*}} = const 8_usize; // CHECK: {{_.*}} = const true; // CHECK: assert(const true diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 00000000000..e71992316dc --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,77 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const main::promoted[0]; + _4 = copy _14; + _3 = copy _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(copy _6, copy _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = copy (*_2)[_6]; ++ _1 = copy (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const main::SLICE; + StorageLive(_11); + _11 = const 1_usize; +- _12 = Len((*_10)); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable]; ++ _12 = const 3_usize; ++ _13 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _9 = copy (*_10)[_11]; ++ _9 = copy (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 00000000000..26de8595768 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,77 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const main::promoted[0]; + _4 = copy _14; + _3 = copy _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(copy _6, copy _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = copy (*_2)[_6]; ++ _1 = copy (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const main::SLICE; + StorageLive(_11); + _11 = const 1_usize; +- _12 = Len((*_10)); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue]; ++ _12 = const 3_usize; ++ _13 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _9 = copy (*_10)[_11]; ++ _9 = copy (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 00000000000..e71992316dc --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,77 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const main::promoted[0]; + _4 = copy _14; + _3 = copy _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(copy _6, copy _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = copy (*_2)[_6]; ++ _1 = copy (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const main::SLICE; + StorageLive(_11); + _11 = const 1_usize; +- _12 = Len((*_10)); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable]; ++ _12 = const 3_usize; ++ _13 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _9 = copy (*_10)[_11]; ++ _9 = copy (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 00000000000..26de8595768 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,77 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const main::promoted[0]; + _4 = copy _14; + _3 = copy _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = Len((*_2)); +- _8 = Lt(copy _6, copy _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = copy (*_2)[_6]; ++ _1 = copy (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const main::SLICE; + StorageLive(_11); + _11 = const 1_usize; +- _12 = Len((*_10)); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue]; ++ _12 = const 3_usize; ++ _13 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _9 = copy (*_10)[_11]; ++ _9 = copy (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs new file mode 100644 index 00000000000..e0e68f9fde5 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.rs @@ -0,0 +1,34 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR slice_len.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( +fn main() { + // CHECK: debug local => [[local:_.*]]; + // CHECK: debug constant => [[constant:_.*]]; + + // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = Lt( + // CHECK-NOT: assert(move _ + // CHECK: {{_.*}} = const 3_usize; + // CHECK: {{_.*}} = const true; + // CHECK: assert(const true, + + // CHECK: [[local]] = copy (*{{_.*}})[1 of 2]; + let local = (&[1u32, 2, 3] as &[u32])[1]; + + // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = Lt( + // CHECK-NOT: assert(move _ + const SLICE: &[u32] = &[1, 2, 3]; + // CHECK: {{_.*}} = const 3_usize; + // CHECK: {{_.*}} = const true; + // CHECK: assert(const true, + + // CHECK-NOT: [[constant]] = {{copy|move}} (*{{_.*}})[_ + // CHECK: [[constant]] = copy (*{{_.*}})[1 of 2]; + let constant = SLICE[1]; +} diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff index b4197c09ac9..60742ef0e9a 100644 --- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff +++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-abort.diff @@ -22,14 +22,14 @@ bb1: { StorageDead(_3); - _4 = PtrMetadata(copy _2); + _4 = Len((*_2)); _5 = const 4_usize; _6 = Ge(move _4, move _5); switchInt(move _6) -> [0: bb2, otherwise: bb3]; } bb2: { - _7 = PtrMetadata(copy _2); + _7 = Len((*_2)); _8 = const 3_usize; _9 = Ge(move _7, move _8); - switchInt(move _9) -> [0: bb7, otherwise: bb8]; diff --git a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff index 4bcb13ca49c..7337a32f525 100644 --- a/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff +++ b/tests/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.panic-unwind.diff @@ -22,14 +22,14 @@ bb1: { StorageDead(_3); - _4 = PtrMetadata(copy _2); + _4 = Len((*_2)); _5 = const 4_usize; _6 = Ge(move _4, move _5); switchInt(move _6) -> [0: bb2, otherwise: bb3]; } bb2: { - _7 = PtrMetadata(copy _2); + _7 = Len((*_2)); _8 = const 3_usize; _9 = Ge(move _7, move _8); - switchInt(move _9) -> [0: bb7, otherwise: bb8]; diff --git a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff index 183b4d2599f..3f052ee19fd 100644 --- a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-abort.diff @@ -53,7 +53,7 @@ StorageLive(_8); - _8 = copy _2; + _8 = const usize::MAX; - _9 = PtrMetadata(copy _1); + _9 = Len((*_1)); - _10 = Lt(copy _8, copy _9); - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable]; + _10 = Lt(const usize::MAX, copy _9); @@ -72,7 +72,7 @@ StorageDead(_5); StorageLive(_11); _11 = const 0_usize; - _12 = PtrMetadata(copy _1); + _12 = Len((*_1)); - _13 = Lt(copy _11, copy _12); - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind unreachable]; + _13 = Lt(const 0_usize, copy _12); diff --git a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff index 03e8aa3bd9b..84b738c7804 100644 --- a/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.constant_index_overflow.GVN.panic-unwind.diff @@ -53,7 +53,7 @@ StorageLive(_8); - _8 = copy _2; + _8 = const usize::MAX; - _9 = PtrMetadata(copy _1); + _9 = Len((*_1)); - _10 = Lt(copy _8, copy _9); - assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue]; + _10 = Lt(const usize::MAX, copy _9); @@ -72,7 +72,7 @@ StorageDead(_5); StorageLive(_11); _11 = const 0_usize; - _12 = PtrMetadata(copy _1); + _12 = Len((*_1)); - _13 = Lt(copy _11, copy _12); - assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind continue]; + _13 = Lt(const 0_usize, copy _12); diff --git a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff b/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff deleted file mode 100644 index 4b077f580f1..00000000000 --- a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-abort.diff +++ /dev/null @@ -1,72 +0,0 @@ -- // MIR for `dedup_multiple_bounds_checks_lengths` before GVN -+ // MIR for `dedup_multiple_bounds_checks_lengths` after GVN - - fn dedup_multiple_bounds_checks_lengths(_1: &[i32]) -> [i32; 3] { - debug x => _1; - let mut _0: [i32; 3]; - let mut _2: i32; - let _3: usize; - let mut _4: usize; - let mut _5: bool; - let mut _6: i32; - let _7: usize; - let mut _8: usize; - let mut _9: bool; - let mut _10: i32; - let _11: usize; - let mut _12: usize; - let mut _13: bool; - - bb0: { - StorageLive(_2); - StorageLive(_3); - _3 = const 42_usize; - _4 = PtrMetadata(copy _1); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; -+ _5 = Lt(const 42_usize, copy _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", copy _4, const 42_usize) -> [success: bb1, unwind unreachable]; - } - - bb1: { -- _2 = copy (*_1)[_3]; -+ _2 = copy (*_1)[42 of 43]; - StorageLive(_6); - StorageLive(_7); - _7 = const 13_usize; -- _8 = PtrMetadata(copy _1); -- _9 = Lt(copy _7, copy _8); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable]; -+ _8 = copy _4; -+ _9 = Lt(const 13_usize, copy _4); -+ assert(move _9, "index out of bounds: the length is {} but the index is {}", copy _4, const 13_usize) -> [success: bb2, unwind unreachable]; - } - - bb2: { -- _6 = copy (*_1)[_7]; -+ _6 = copy (*_1)[13 of 14]; - StorageLive(_10); - StorageLive(_11); - _11 = const 7_usize; -- _12 = PtrMetadata(copy _1); -- _13 = Lt(copy _11, copy _12); -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb3, unwind unreachable]; -+ _12 = copy _4; -+ _13 = Lt(const 7_usize, copy _4); -+ assert(move _13, "index out of bounds: the length is {} but the index is {}", copy _4, const 7_usize) -> [success: bb3, unwind unreachable]; - } - - bb3: { -- _10 = copy (*_1)[_11]; -+ _10 = copy (*_1)[7 of 8]; - _0 = [move _2, move _6, move _10]; - StorageDead(_10); - StorageDead(_6); - StorageDead(_2); - StorageDead(_11); - StorageDead(_7); - StorageDead(_3); - return; - } - } - diff --git a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff b/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff deleted file mode 100644 index 87e69d44006..00000000000 --- a/tests/mir-opt/gvn.dedup_multiple_bounds_checks_lengths.GVN.panic-unwind.diff +++ /dev/null @@ -1,72 +0,0 @@ -- // MIR for `dedup_multiple_bounds_checks_lengths` before GVN -+ // MIR for `dedup_multiple_bounds_checks_lengths` after GVN - - fn dedup_multiple_bounds_checks_lengths(_1: &[i32]) -> [i32; 3] { - debug x => _1; - let mut _0: [i32; 3]; - let mut _2: i32; - let _3: usize; - let mut _4: usize; - let mut _5: bool; - let mut _6: i32; - let _7: usize; - let mut _8: usize; - let mut _9: bool; - let mut _10: i32; - let _11: usize; - let mut _12: usize; - let mut _13: bool; - - bb0: { - StorageLive(_2); - StorageLive(_3); - _3 = const 42_usize; - _4 = PtrMetadata(copy _1); -- _5 = Lt(copy _3, copy _4); -- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; -+ _5 = Lt(const 42_usize, copy _4); -+ assert(move _5, "index out of bounds: the length is {} but the index is {}", copy _4, const 42_usize) -> [success: bb1, unwind continue]; - } - - bb1: { -- _2 = copy (*_1)[_3]; -+ _2 = copy (*_1)[42 of 43]; - StorageLive(_6); - StorageLive(_7); - _7 = const 13_usize; -- _8 = PtrMetadata(copy _1); -- _9 = Lt(copy _7, copy _8); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue]; -+ _8 = copy _4; -+ _9 = Lt(const 13_usize, copy _4); -+ assert(move _9, "index out of bounds: the length is {} but the index is {}", copy _4, const 13_usize) -> [success: bb2, unwind continue]; - } - - bb2: { -- _6 = copy (*_1)[_7]; -+ _6 = copy (*_1)[13 of 14]; - StorageLive(_10); - StorageLive(_11); - _11 = const 7_usize; -- _12 = PtrMetadata(copy _1); -- _13 = Lt(copy _11, copy _12); -- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb3, unwind continue]; -+ _12 = copy _4; -+ _13 = Lt(const 7_usize, copy _4); -+ assert(move _13, "index out of bounds: the length is {} but the index is {}", copy _4, const 7_usize) -> [success: bb3, unwind continue]; - } - - bb3: { -- _10 = copy (*_1)[_11]; -+ _10 = copy (*_1)[7 of 8]; - _0 = [move _2, move _6, move _10]; - StorageDead(_10); - StorageDead(_6); - StorageDead(_2); - StorageDead(_11); - StorageDead(_7); - StorageDead(_3); - return; - } - } - diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff index 7f44176b756..d4b22d05f6c 100644 --- a/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-abort.diff @@ -10,11 +10,13 @@ let _5: (); let mut _6: T; let _7: usize; - let mut _8: bool; - let _9: (); - let mut _10: T; - let _11: usize; - let mut _12: bool; + let mut _8: usize; + let mut _9: bool; + let _10: (); + let mut _11: T; + let _12: usize; + let mut _13: usize; + let mut _14: bool; scope 1 { debug a => _3; } @@ -30,10 +32,12 @@ StorageLive(_6); StorageLive(_7); _7 = const 0_usize; -- _8 = Lt(copy _7, const N); -- assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, copy _7) -> [success: bb1, unwind unreachable]; -+ _8 = Lt(const 0_usize, const N); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable]; +- _8 = Len(_3); +- _9 = Lt(copy _7, copy _8); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb1, unwind unreachable]; ++ _8 = const N; ++ _9 = Lt(const 0_usize, const N); ++ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind unreachable]; } bb1: { @@ -47,27 +51,29 @@ StorageDead(_6); StorageDead(_7); StorageDead(_5); - StorageLive(_9); StorageLive(_10); StorageLive(_11); - _11 = copy _2; -- _12 = Lt(copy _11, const N); -- assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _11) -> [success: bb3, unwind unreachable]; -+ _12 = Lt(copy _2, const N); -+ assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind unreachable]; + StorageLive(_12); + _12 = copy _2; +- _13 = Len(_3); +- _14 = Lt(copy _12, copy _13); +- assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, copy _12) -> [success: bb3, unwind unreachable]; ++ _13 = const N; ++ _14 = Lt(copy _2, const N); ++ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind unreachable]; } bb3: { -- _10 = copy _3[_11]; -- _9 = opaque::<T>(move _10) -> [return: bb4, unwind unreachable]; -+ _10 = copy _1; -+ _9 = opaque::<T>(copy _1) -> [return: bb4, unwind unreachable]; +- _11 = copy _3[_12]; +- _10 = opaque::<T>(move _11) -> [return: bb4, unwind unreachable]; ++ _11 = copy _1; ++ _10 = opaque::<T>(copy _1) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_10); StorageDead(_11); - StorageDead(_9); + StorageDead(_12); + StorageDead(_10); _0 = const (); StorageDead(_3); return; diff --git a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff index d34882d725f..708c0f92e54 100644 --- a/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.repeated_index.GVN.panic-unwind.diff @@ -10,11 +10,13 @@ let _5: (); let mut _6: T; let _7: usize; - let mut _8: bool; - let _9: (); - let mut _10: T; - let _11: usize; - let mut _12: bool; + let mut _8: usize; + let mut _9: bool; + let _10: (); + let mut _11: T; + let _12: usize; + let mut _13: usize; + let mut _14: bool; scope 1 { debug a => _3; } @@ -30,10 +32,12 @@ StorageLive(_6); StorageLive(_7); _7 = const 0_usize; -- _8 = Lt(copy _7, const N); -- assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, copy _7) -> [success: bb1, unwind continue]; -+ _8 = Lt(const 0_usize, const N); -+ assert(move _8, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue]; +- _8 = Len(_3); +- _9 = Lt(copy _7, copy _8); +- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb1, unwind continue]; ++ _8 = const N; ++ _9 = Lt(const 0_usize, const N); ++ assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb1, unwind continue]; } bb1: { @@ -47,27 +51,29 @@ StorageDead(_6); StorageDead(_7); StorageDead(_5); - StorageLive(_9); StorageLive(_10); StorageLive(_11); - _11 = copy _2; -- _12 = Lt(copy _11, const N); -- assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _11) -> [success: bb3, unwind continue]; -+ _12 = Lt(copy _2, const N); -+ assert(move _12, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind continue]; + StorageLive(_12); + _12 = copy _2; +- _13 = Len(_3); +- _14 = Lt(copy _12, copy _13); +- assert(move _14, "index out of bounds: the length is {} but the index is {}", move _13, copy _12) -> [success: bb3, unwind continue]; ++ _13 = const N; ++ _14 = Lt(copy _2, const N); ++ assert(move _14, "index out of bounds: the length is {} but the index is {}", const N, copy _2) -> [success: bb3, unwind continue]; } bb3: { -- _10 = copy _3[_11]; -- _9 = opaque::<T>(move _10) -> [return: bb4, unwind continue]; -+ _10 = copy _1; -+ _9 = opaque::<T>(copy _1) -> [return: bb4, unwind continue]; +- _11 = copy _3[_12]; +- _10 = opaque::<T>(move _11) -> [return: bb4, unwind continue]; ++ _11 = copy _1; ++ _10 = opaque::<T>(copy _1) -> [return: bb4, unwind continue]; } bb4: { - StorageDead(_10); StorageDead(_11); - StorageDead(_9); + StorageDead(_12); + StorageDead(_10); _0 = const (); StorageDead(_3); return; diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs index c895a579259..10d1ccfdece 100644 --- a/tests/mir-opt/gvn.rs +++ b/tests/mir-opt/gvn.rs @@ -835,25 +835,6 @@ fn array_len(x: &mut [i32; 42]) -> usize { std::intrinsics::ptr_metadata(x) } -// Check that we only load the length once, rather than all 3 times. -fn dedup_multiple_bounds_checks_lengths(x: &[i32]) -> [i32; 3] { - // CHECK-LABEL: fn dedup_multiple_bounds_checks_lengths - // CHECK: [[LEN:_.+]] = PtrMetadata(copy _1); - // CHECK: Lt(const 42_usize, copy [[LEN]]); - // CHECK: assert{{.+}}copy [[LEN]] - // CHECK: [[A:_.+]] = copy (*_1)[42 of 43]; - // CHECK-NOT: PtrMetadata - // CHECK: Lt(const 13_usize, copy [[LEN]]); - // CHECK: assert{{.+}}copy [[LEN]] - // CHECK: [[B:_.+]] = copy (*_1)[13 of 14]; - // CHECK-NOT: PtrMetadata - // CHECK: Lt(const 7_usize, copy [[LEN]]); - // CHECK: assert{{.+}}copy [[LEN]] - // CHECK: [[C:_.+]] = copy (*_1)[7 of 8]; - // CHECK: _0 = [move [[A]], move [[B]], move [[C]]] - [x[42], x[13], x[7]] -} - #[custom_mir(dialect = "runtime")] fn generic_cast_metadata<T, A: ?Sized, B: ?Sized>(ps: *const [T], pa: *const A, pb: *const B) { // CHECK-LABEL: fn generic_cast_metadata @@ -1128,7 +1109,6 @@ enum Never {} // EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff // EMIT_MIR gvn.manual_slice_mut_len.GVN.diff // EMIT_MIR gvn.array_len.GVN.diff -// EMIT_MIR gvn.dedup_multiple_bounds_checks_lengths.GVN.diff // EMIT_MIR gvn.generic_cast_metadata.GVN.diff // EMIT_MIR gvn.cast_pointer_eq.GVN.diff // EMIT_MIR gvn.aggregate_struct_then_transmute.GVN.diff diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff index 1b305e746f5..6b6152c1117 100644 --- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-abort.diff @@ -10,60 +10,62 @@ let mut _6: &i32; let _7: &i32; let _8: usize; - let mut _9: bool; - let mut _11: *const dyn std::marker::Send; - let _12: &dyn std::marker::Send; - let mut _13: &i32; - let _14: &i32; - let _15: usize; - let mut _16: bool; - let _17: (); + let mut _9: usize; + let mut _10: bool; + let mut _12: *const dyn std::marker::Send; + let _13: &dyn std::marker::Send; + let mut _14: &i32; + let _15: &i32; + let _16: usize; + let mut _17: usize; let mut _18: bool; - let mut _19: *const dyn std::marker::Send; - let mut _20: *const dyn std::marker::Send; + let _19: (); + let mut _20: bool; let mut _21: *const dyn std::marker::Send; - let _22: (); - let mut _23: bool; - let mut _24: *const dyn std::marker::Send; - let mut _25: *const dyn std::marker::Send; + let mut _22: *const dyn std::marker::Send; + let mut _23: *const dyn std::marker::Send; + let _24: (); + let mut _25: bool; let mut _26: *const dyn std::marker::Send; - let _27: (); - let mut _28: bool; - let mut _29: *const dyn std::marker::Send; - let mut _30: *const dyn std::marker::Send; + let mut _27: *const dyn std::marker::Send; + let mut _28: *const dyn std::marker::Send; + let _29: (); + let mut _30: bool; let mut _31: *const dyn std::marker::Send; - let _32: (); - let mut _33: bool; - let mut _34: *const dyn std::marker::Send; - let mut _35: *const dyn std::marker::Send; + let mut _32: *const dyn std::marker::Send; + let mut _33: *const dyn std::marker::Send; + let _34: (); + let mut _35: bool; let mut _36: *const dyn std::marker::Send; - let _37: (); - let mut _38: bool; - let mut _39: *const dyn std::marker::Send; - let mut _40: *const dyn std::marker::Send; + let mut _37: *const dyn std::marker::Send; + let mut _38: *const dyn std::marker::Send; + let _39: (); + let mut _40: bool; let mut _41: *const dyn std::marker::Send; - let _42: (); - let mut _43: bool; - let mut _44: *const dyn std::marker::Send; - let mut _45: *const dyn std::marker::Send; + let mut _42: *const dyn std::marker::Send; + let mut _43: *const dyn std::marker::Send; + let _44: (); + let mut _45: bool; let mut _46: *const dyn std::marker::Send; - let mut _47: &[i32; 2]; + let mut _47: *const dyn std::marker::Send; + let mut _48: *const dyn std::marker::Send; + let mut _49: &[i32; 2]; scope 1 { debug slice => _1; let _3: *const dyn std::marker::Send; scope 2 { debug a => _3; - let _10: *const dyn std::marker::Send; + let _11: *const dyn std::marker::Send; scope 3 { - debug b => _10; + debug b => _11; } } } bb0: { StorageLive(_1); - _47 = const wide_ptr_same_provenance::promoted[0]; - _1 = &(*_47); + _49 = const wide_ptr_same_provenance::promoted[0]; + _1 = &(*_49); StorageLive(_3); - StorageLive(_4); + nop; @@ -72,9 +74,11 @@ StorageLive(_7); StorageLive(_8); _8 = const 0_usize; -- _9 = Lt(copy _8, const 2_usize); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _8) -> [success: bb1, unwind unreachable]; -+ _9 = const true; +- _9 = Len((*_1)); +- _10 = Lt(copy _8, copy _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb1, unwind unreachable]; ++ _9 = const 2_usize; ++ _10 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 0_usize) -> [success: bb1, unwind unreachable]; } @@ -91,168 +95,170 @@ + nop; StorageDead(_7); StorageDead(_5); - StorageLive(_10); -- StorageLive(_11); + StorageLive(_11); +- StorageLive(_12); + nop; - StorageLive(_12); StorageLive(_13); StorageLive(_14); StorageLive(_15); - _15 = const 1_usize; -- _16 = Lt(copy _15, const 2_usize); -- assert(move _16, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _15) -> [success: bb2, unwind unreachable]; -+ _16 = const true; + StorageLive(_16); + _16 = const 1_usize; +- _17 = Len((*_1)); +- _18 = Lt(copy _16, copy _17); +- assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, copy _16) -> [success: bb2, unwind unreachable]; ++ _17 = const 2_usize; ++ _18 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 1_usize) -> [success: bb2, unwind unreachable]; } bb2: { -- _14 = &(*_1)[_15]; -+ _14 = &(*_1)[1 of 2]; - _13 = &(*_14); - _12 = move _13 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast)); - StorageDead(_13); - _11 = &raw const (*_12); -- _10 = move _11 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -- StorageDead(_11); -+ _10 = copy _11; -+ nop; +- _15 = &(*_1)[_16]; ++ _15 = &(*_1)[1 of 2]; + _14 = &(*_15); + _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast)); StorageDead(_14); - StorageDead(_12); - StorageLive(_17); - StorageLive(_18); + _12 = &raw const (*_13); +- _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); +- StorageDead(_12); ++ _11 = copy _12; ++ nop; + StorageDead(_15); + StorageDead(_13); StorageLive(_19); -- _19 = copy _3; -+ _19 = copy _4; StorageLive(_20); StorageLive(_21); -- _21 = copy _10; -- _20 = move _21 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _21 = copy _11; -+ _20 = copy _11; +- _21 = copy _3; ++ _21 = copy _4; + StorageLive(_22); + StorageLive(_23); +- _23 = copy _11; +- _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _23 = copy _12; ++ _22 = copy _12; + StorageDead(_23); +- _20 = Eq(move _21, move _22); ++ _20 = Eq(copy _4, copy _12); + StorageDead(_22); StorageDead(_21); -- _18 = Eq(move _19, move _20); -+ _18 = Eq(copy _4, copy _11); - StorageDead(_20); - StorageDead(_19); - _17 = opaque::<bool>(move _18) -> [return: bb3, unwind unreachable]; + _19 = opaque::<bool>(move _20) -> [return: bb3, unwind unreachable]; } bb3: { - StorageDead(_18); - StorageDead(_17); - StorageLive(_22); - StorageLive(_23); + StorageDead(_20); + StorageDead(_19); StorageLive(_24); -- _24 = copy _3; -+ _24 = copy _4; StorageLive(_25); StorageLive(_26); -- _26 = copy _10; -- _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _26 = copy _11; -+ _25 = copy _11; +- _26 = copy _3; ++ _26 = copy _4; + StorageLive(_27); + StorageLive(_28); +- _28 = copy _11; +- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _28 = copy _12; ++ _27 = copy _12; + StorageDead(_28); +- _25 = Ne(move _26, move _27); ++ _25 = Ne(copy _4, copy _12); + StorageDead(_27); StorageDead(_26); -- _23 = Ne(move _24, move _25); -+ _23 = Ne(copy _4, copy _11); - StorageDead(_25); - StorageDead(_24); - _22 = opaque::<bool>(move _23) -> [return: bb4, unwind unreachable]; + _24 = opaque::<bool>(move _25) -> [return: bb4, unwind unreachable]; } bb4: { - StorageDead(_23); - StorageDead(_22); - StorageLive(_27); - StorageLive(_28); + StorageDead(_25); + StorageDead(_24); StorageLive(_29); -- _29 = copy _3; -+ _29 = copy _4; StorageLive(_30); StorageLive(_31); -- _31 = copy _10; -- _30 = move _31 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _31 = copy _11; -+ _30 = copy _11; +- _31 = copy _3; ++ _31 = copy _4; + StorageLive(_32); + StorageLive(_33); +- _33 = copy _11; +- _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _33 = copy _12; ++ _32 = copy _12; + StorageDead(_33); +- _30 = Lt(move _31, move _32); ++ _30 = Lt(copy _4, copy _12); + StorageDead(_32); StorageDead(_31); -- _28 = Lt(move _29, move _30); -+ _28 = Lt(copy _4, copy _11); - StorageDead(_30); - StorageDead(_29); - _27 = opaque::<bool>(move _28) -> [return: bb5, unwind unreachable]; + _29 = opaque::<bool>(move _30) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_28); - StorageDead(_27); - StorageLive(_32); - StorageLive(_33); + StorageDead(_30); + StorageDead(_29); StorageLive(_34); -- _34 = copy _3; -+ _34 = copy _4; StorageLive(_35); StorageLive(_36); -- _36 = copy _10; -- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _36 = copy _11; -+ _35 = copy _11; +- _36 = copy _3; ++ _36 = copy _4; + StorageLive(_37); + StorageLive(_38); +- _38 = copy _11; +- _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _38 = copy _12; ++ _37 = copy _12; + StorageDead(_38); +- _35 = Le(move _36, move _37); ++ _35 = Le(copy _4, copy _12); + StorageDead(_37); StorageDead(_36); -- _33 = Le(move _34, move _35); -+ _33 = Le(copy _4, copy _11); - StorageDead(_35); - StorageDead(_34); - _32 = opaque::<bool>(move _33) -> [return: bb6, unwind unreachable]; + _34 = opaque::<bool>(move _35) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_33); - StorageDead(_32); - StorageLive(_37); - StorageLive(_38); + StorageDead(_35); + StorageDead(_34); StorageLive(_39); -- _39 = copy _3; -+ _39 = copy _4; StorageLive(_40); StorageLive(_41); -- _41 = copy _10; -- _40 = move _41 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _41 = copy _11; -+ _40 = copy _11; +- _41 = copy _3; ++ _41 = copy _4; + StorageLive(_42); + StorageLive(_43); +- _43 = copy _11; +- _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _43 = copy _12; ++ _42 = copy _12; + StorageDead(_43); +- _40 = Gt(move _41, move _42); ++ _40 = Gt(copy _4, copy _12); + StorageDead(_42); StorageDead(_41); -- _38 = Gt(move _39, move _40); -+ _38 = Gt(copy _4, copy _11); - StorageDead(_40); - StorageDead(_39); - _37 = opaque::<bool>(move _38) -> [return: bb7, unwind unreachable]; + _39 = opaque::<bool>(move _40) -> [return: bb7, unwind unreachable]; } bb7: { - StorageDead(_38); - StorageDead(_37); - StorageLive(_42); - StorageLive(_43); + StorageDead(_40); + StorageDead(_39); StorageLive(_44); -- _44 = copy _3; -+ _44 = copy _4; StorageLive(_45); StorageLive(_46); -- _46 = copy _10; -- _45 = move _46 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _46 = copy _11; -+ _45 = copy _11; +- _46 = copy _3; ++ _46 = copy _4; + StorageLive(_47); + StorageLive(_48); +- _48 = copy _11; +- _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _48 = copy _12; ++ _47 = copy _12; + StorageDead(_48); +- _45 = Ge(move _46, move _47); ++ _45 = Ge(copy _4, copy _12); + StorageDead(_47); StorageDead(_46); -- _43 = Ge(move _44, move _45); -+ _43 = Ge(copy _4, copy _11); - StorageDead(_45); - StorageDead(_44); - _42 = opaque::<bool>(move _43) -> [return: bb8, unwind unreachable]; + _44 = opaque::<bool>(move _45) -> [return: bb8, unwind unreachable]; } bb8: { - StorageDead(_43); - StorageDead(_42); + StorageDead(_45); + StorageDead(_44); _0 = const (); - StorageDead(_15); - StorageDead(_10); + StorageDead(_16); + StorageDead(_11); StorageDead(_8); StorageDead(_3); StorageDead(_1); diff --git a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff index e418ecf25bd..093c1ec6ce3 100644 --- a/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.wide_ptr_same_provenance.GVN.panic-unwind.diff @@ -10,60 +10,62 @@ let mut _6: &i32; let _7: &i32; let _8: usize; - let mut _9: bool; - let mut _11: *const dyn std::marker::Send; - let _12: &dyn std::marker::Send; - let mut _13: &i32; - let _14: &i32; - let _15: usize; - let mut _16: bool; - let _17: (); + let mut _9: usize; + let mut _10: bool; + let mut _12: *const dyn std::marker::Send; + let _13: &dyn std::marker::Send; + let mut _14: &i32; + let _15: &i32; + let _16: usize; + let mut _17: usize; let mut _18: bool; - let mut _19: *const dyn std::marker::Send; - let mut _20: *const dyn std::marker::Send; + let _19: (); + let mut _20: bool; let mut _21: *const dyn std::marker::Send; - let _22: (); - let mut _23: bool; - let mut _24: *const dyn std::marker::Send; - let mut _25: *const dyn std::marker::Send; + let mut _22: *const dyn std::marker::Send; + let mut _23: *const dyn std::marker::Send; + let _24: (); + let mut _25: bool; let mut _26: *const dyn std::marker::Send; - let _27: (); - let mut _28: bool; - let mut _29: *const dyn std::marker::Send; - let mut _30: *const dyn std::marker::Send; + let mut _27: *const dyn std::marker::Send; + let mut _28: *const dyn std::marker::Send; + let _29: (); + let mut _30: bool; let mut _31: *const dyn std::marker::Send; - let _32: (); - let mut _33: bool; - let mut _34: *const dyn std::marker::Send; - let mut _35: *const dyn std::marker::Send; + let mut _32: *const dyn std::marker::Send; + let mut _33: *const dyn std::marker::Send; + let _34: (); + let mut _35: bool; let mut _36: *const dyn std::marker::Send; - let _37: (); - let mut _38: bool; - let mut _39: *const dyn std::marker::Send; - let mut _40: *const dyn std::marker::Send; + let mut _37: *const dyn std::marker::Send; + let mut _38: *const dyn std::marker::Send; + let _39: (); + let mut _40: bool; let mut _41: *const dyn std::marker::Send; - let _42: (); - let mut _43: bool; - let mut _44: *const dyn std::marker::Send; - let mut _45: *const dyn std::marker::Send; + let mut _42: *const dyn std::marker::Send; + let mut _43: *const dyn std::marker::Send; + let _44: (); + let mut _45: bool; let mut _46: *const dyn std::marker::Send; - let mut _47: &[i32; 2]; + let mut _47: *const dyn std::marker::Send; + let mut _48: *const dyn std::marker::Send; + let mut _49: &[i32; 2]; scope 1 { debug slice => _1; let _3: *const dyn std::marker::Send; scope 2 { debug a => _3; - let _10: *const dyn std::marker::Send; + let _11: *const dyn std::marker::Send; scope 3 { - debug b => _10; + debug b => _11; } } } bb0: { StorageLive(_1); - _47 = const wide_ptr_same_provenance::promoted[0]; - _1 = &(*_47); + _49 = const wide_ptr_same_provenance::promoted[0]; + _1 = &(*_49); StorageLive(_3); - StorageLive(_4); + nop; @@ -72,9 +74,11 @@ StorageLive(_7); StorageLive(_8); _8 = const 0_usize; -- _9 = Lt(copy _8, const 2_usize); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _8) -> [success: bb1, unwind continue]; -+ _9 = const true; +- _9 = Len((*_1)); +- _10 = Lt(copy _8, copy _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb1, unwind continue]; ++ _9 = const 2_usize; ++ _10 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 0_usize) -> [success: bb1, unwind continue]; } @@ -91,168 +95,170 @@ + nop; StorageDead(_7); StorageDead(_5); - StorageLive(_10); -- StorageLive(_11); + StorageLive(_11); +- StorageLive(_12); + nop; - StorageLive(_12); StorageLive(_13); StorageLive(_14); StorageLive(_15); - _15 = const 1_usize; -- _16 = Lt(copy _15, const 2_usize); -- assert(move _16, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _15) -> [success: bb2, unwind continue]; -+ _16 = const true; + StorageLive(_16); + _16 = const 1_usize; +- _17 = Len((*_1)); +- _18 = Lt(copy _16, copy _17); +- assert(move _18, "index out of bounds: the length is {} but the index is {}", move _17, copy _16) -> [success: bb2, unwind continue]; ++ _17 = const 2_usize; ++ _18 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 2_usize, const 1_usize) -> [success: bb2, unwind continue]; } bb2: { -- _14 = &(*_1)[_15]; -+ _14 = &(*_1)[1 of 2]; - _13 = &(*_14); - _12 = move _13 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast)); - StorageDead(_13); - _11 = &raw const (*_12); -- _10 = move _11 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -- StorageDead(_11); -+ _10 = copy _11; -+ nop; +- _15 = &(*_1)[_16]; ++ _15 = &(*_1)[1 of 2]; + _14 = &(*_15); + _13 = move _14 as &dyn std::marker::Send (PointerCoercion(Unsize, AsCast)); StorageDead(_14); - StorageDead(_12); - StorageLive(_17); - StorageLive(_18); + _12 = &raw const (*_13); +- _11 = move _12 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); +- StorageDead(_12); ++ _11 = copy _12; ++ nop; + StorageDead(_15); + StorageDead(_13); StorageLive(_19); -- _19 = copy _3; -+ _19 = copy _4; StorageLive(_20); StorageLive(_21); -- _21 = copy _10; -- _20 = move _21 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _21 = copy _11; -+ _20 = copy _11; +- _21 = copy _3; ++ _21 = copy _4; + StorageLive(_22); + StorageLive(_23); +- _23 = copy _11; +- _22 = move _23 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _23 = copy _12; ++ _22 = copy _12; + StorageDead(_23); +- _20 = Eq(move _21, move _22); ++ _20 = Eq(copy _4, copy _12); + StorageDead(_22); StorageDead(_21); -- _18 = Eq(move _19, move _20); -+ _18 = Eq(copy _4, copy _11); - StorageDead(_20); - StorageDead(_19); - _17 = opaque::<bool>(move _18) -> [return: bb3, unwind continue]; + _19 = opaque::<bool>(move _20) -> [return: bb3, unwind continue]; } bb3: { - StorageDead(_18); - StorageDead(_17); - StorageLive(_22); - StorageLive(_23); + StorageDead(_20); + StorageDead(_19); StorageLive(_24); -- _24 = copy _3; -+ _24 = copy _4; StorageLive(_25); StorageLive(_26); -- _26 = copy _10; -- _25 = move _26 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _26 = copy _11; -+ _25 = copy _11; +- _26 = copy _3; ++ _26 = copy _4; + StorageLive(_27); + StorageLive(_28); +- _28 = copy _11; +- _27 = move _28 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _28 = copy _12; ++ _27 = copy _12; + StorageDead(_28); +- _25 = Ne(move _26, move _27); ++ _25 = Ne(copy _4, copy _12); + StorageDead(_27); StorageDead(_26); -- _23 = Ne(move _24, move _25); -+ _23 = Ne(copy _4, copy _11); - StorageDead(_25); - StorageDead(_24); - _22 = opaque::<bool>(move _23) -> [return: bb4, unwind continue]; + _24 = opaque::<bool>(move _25) -> [return: bb4, unwind continue]; } bb4: { - StorageDead(_23); - StorageDead(_22); - StorageLive(_27); - StorageLive(_28); + StorageDead(_25); + StorageDead(_24); StorageLive(_29); -- _29 = copy _3; -+ _29 = copy _4; StorageLive(_30); StorageLive(_31); -- _31 = copy _10; -- _30 = move _31 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _31 = copy _11; -+ _30 = copy _11; +- _31 = copy _3; ++ _31 = copy _4; + StorageLive(_32); + StorageLive(_33); +- _33 = copy _11; +- _32 = move _33 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _33 = copy _12; ++ _32 = copy _12; + StorageDead(_33); +- _30 = Lt(move _31, move _32); ++ _30 = Lt(copy _4, copy _12); + StorageDead(_32); StorageDead(_31); -- _28 = Lt(move _29, move _30); -+ _28 = Lt(copy _4, copy _11); - StorageDead(_30); - StorageDead(_29); - _27 = opaque::<bool>(move _28) -> [return: bb5, unwind continue]; + _29 = opaque::<bool>(move _30) -> [return: bb5, unwind continue]; } bb5: { - StorageDead(_28); - StorageDead(_27); - StorageLive(_32); - StorageLive(_33); + StorageDead(_30); + StorageDead(_29); StorageLive(_34); -- _34 = copy _3; -+ _34 = copy _4; StorageLive(_35); StorageLive(_36); -- _36 = copy _10; -- _35 = move _36 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _36 = copy _11; -+ _35 = copy _11; +- _36 = copy _3; ++ _36 = copy _4; + StorageLive(_37); + StorageLive(_38); +- _38 = copy _11; +- _37 = move _38 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _38 = copy _12; ++ _37 = copy _12; + StorageDead(_38); +- _35 = Le(move _36, move _37); ++ _35 = Le(copy _4, copy _12); + StorageDead(_37); StorageDead(_36); -- _33 = Le(move _34, move _35); -+ _33 = Le(copy _4, copy _11); - StorageDead(_35); - StorageDead(_34); - _32 = opaque::<bool>(move _33) -> [return: bb6, unwind continue]; + _34 = opaque::<bool>(move _35) -> [return: bb6, unwind continue]; } bb6: { - StorageDead(_33); - StorageDead(_32); - StorageLive(_37); - StorageLive(_38); + StorageDead(_35); + StorageDead(_34); StorageLive(_39); -- _39 = copy _3; -+ _39 = copy _4; StorageLive(_40); StorageLive(_41); -- _41 = copy _10; -- _40 = move _41 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _41 = copy _11; -+ _40 = copy _11; +- _41 = copy _3; ++ _41 = copy _4; + StorageLive(_42); + StorageLive(_43); +- _43 = copy _11; +- _42 = move _43 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _43 = copy _12; ++ _42 = copy _12; + StorageDead(_43); +- _40 = Gt(move _41, move _42); ++ _40 = Gt(copy _4, copy _12); + StorageDead(_42); StorageDead(_41); -- _38 = Gt(move _39, move _40); -+ _38 = Gt(copy _4, copy _11); - StorageDead(_40); - StorageDead(_39); - _37 = opaque::<bool>(move _38) -> [return: bb7, unwind continue]; + _39 = opaque::<bool>(move _40) -> [return: bb7, unwind continue]; } bb7: { - StorageDead(_38); - StorageDead(_37); - StorageLive(_42); - StorageLive(_43); + StorageDead(_40); + StorageDead(_39); StorageLive(_44); -- _44 = copy _3; -+ _44 = copy _4; StorageLive(_45); StorageLive(_46); -- _46 = copy _10; -- _45 = move _46 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); -+ _46 = copy _11; -+ _45 = copy _11; +- _46 = copy _3; ++ _46 = copy _4; + StorageLive(_47); + StorageLive(_48); +- _48 = copy _11; +- _47 = move _48 as *const dyn std::marker::Send (PointerCoercion(Unsize, Implicit)); ++ _48 = copy _12; ++ _47 = copy _12; + StorageDead(_48); +- _45 = Ge(move _46, move _47); ++ _45 = Ge(copy _4, copy _12); + StorageDead(_47); StorageDead(_46); -- _43 = Ge(move _44, move _45); -+ _43 = Ge(copy _4, copy _11); - StorageDead(_45); - StorageDead(_44); - _42 = opaque::<bool>(move _43) -> [return: bb8, unwind continue]; + _44 = opaque::<bool>(move _45) -> [return: bb8, unwind continue]; } bb8: { - StorageDead(_43); - StorageDead(_42); + StorageDead(_45); + StorageDead(_44); _0 = const (); - StorageDead(_15); - StorageDead(_10); + StorageDead(_16); + StorageDead(_11); StorageDead(_8); StorageDead(_3); StorageDead(_1); diff --git a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff new file mode 100644 index 00000000000..f39df7ffca0 --- /dev/null +++ b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff @@ -0,0 +1,77 @@ +- // MIR for `norm2` before InstSimplify-after-simplifycfg ++ // MIR for `norm2` after InstSimplify-after-simplifycfg + + fn norm2(_1: [f32; 2]) -> f32 { + debug x => _1; + let mut _0: f32; + let _2: f32; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + let _7: usize; + let mut _8: usize; + let mut _9: bool; + let mut _10: f32; + let mut _11: f32; + let mut _12: f32; + let mut _13: f32; + let mut _14: f32; + let mut _15: f32; + scope 1 { + debug a => _2; + let _6: f32; + scope 2 { + debug b => _6; + } + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = const 0_usize; +- _4 = Len(_1); ++ _4 = const 2_usize; + _5 = Lt(copy _3, copy _4); + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _2 = copy _1[_3]; + StorageDead(_3); + StorageLive(_6); + StorageLive(_7); + _7 = const 1_usize; +- _8 = Len(_1); ++ _8 = const 2_usize; + _9 = Lt(copy _7, copy _8); + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind unreachable]; + } + + bb2: { + _6 = copy _1[_7]; + StorageDead(_7); + StorageLive(_10); + StorageLive(_11); + _11 = copy _2; + StorageLive(_12); + _12 = copy _2; + _10 = Mul(move _11, move _12); + StorageDead(_12); + StorageDead(_11); + StorageLive(_13); + StorageLive(_14); + _14 = copy _6; + StorageLive(_15); + _15 = copy _6; + _13 = Mul(move _14, move _15); + StorageDead(_15); + StorageDead(_14); + _0 = Add(move _10, move _13); + StorageDead(_13); + StorageDead(_10); + StorageDead(_6); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff new file mode 100644 index 00000000000..0e7d5653c68 --- /dev/null +++ b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff @@ -0,0 +1,77 @@ +- // MIR for `norm2` before InstSimplify-after-simplifycfg ++ // MIR for `norm2` after InstSimplify-after-simplifycfg + + fn norm2(_1: [f32; 2]) -> f32 { + debug x => _1; + let mut _0: f32; + let _2: f32; + let _3: usize; + let mut _4: usize; + let mut _5: bool; + let _7: usize; + let mut _8: usize; + let mut _9: bool; + let mut _10: f32; + let mut _11: f32; + let mut _12: f32; + let mut _13: f32; + let mut _14: f32; + let mut _15: f32; + scope 1 { + debug a => _2; + let _6: f32; + scope 2 { + debug b => _6; + } + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = const 0_usize; +- _4 = Len(_1); ++ _4 = const 2_usize; + _5 = Lt(copy _3, copy _4); + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind continue]; + } + + bb1: { + _2 = copy _1[_3]; + StorageDead(_3); + StorageLive(_6); + StorageLive(_7); + _7 = const 1_usize; +- _8 = Len(_1); ++ _8 = const 2_usize; + _9 = Lt(copy _7, copy _8); + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb2, unwind continue]; + } + + bb2: { + _6 = copy _1[_7]; + StorageDead(_7); + StorageLive(_10); + StorageLive(_11); + _11 = copy _2; + StorageLive(_12); + _12 = copy _2; + _10 = Mul(move _11, move _12); + StorageDead(_12); + StorageDead(_11); + StorageLive(_13); + StorageLive(_14); + _14 = copy _6; + StorageLive(_15); + _15 = copy _6; + _13 = Mul(move _14, move _15); + StorageDead(_15); + StorageDead(_14); + _0 = Add(move _10, move _13); + StorageDead(_13); + StorageDead(_10); + StorageDead(_6); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/instsimplify/combine_array_len.rs b/tests/mir-opt/instsimplify/combine_array_len.rs new file mode 100644 index 00000000000..91f43f75689 --- /dev/null +++ b/tests/mir-opt/instsimplify/combine_array_len.rs @@ -0,0 +1,15 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ test-mir-pass: InstSimplify-after-simplifycfg + +// EMIT_MIR combine_array_len.norm2.InstSimplify-after-simplifycfg.diff +fn norm2(x: [f32; 2]) -> f32 { + // CHECK-LABEL: fn norm2( + // CHECK-NOT: Len( + let a = x[0]; + let b = x[1]; + a * a + b * b +} + +fn main() { + assert_eq!(norm2([3.0, 4.0]), 5.0 * 5.0); +} diff --git a/tests/mir-opt/issue_72181.foo.built.after.mir b/tests/mir-opt/issue_72181.foo.built.after.mir index 7593b795432..314cf8b367f 100644 --- a/tests/mir-opt/issue_72181.foo.built.after.mir +++ b/tests/mir-opt/issue_72181.foo.built.after.mir @@ -4,14 +4,15 @@ fn foo(_1: [(Never, u32); 1]) -> u32 { debug xs => _1; let mut _0: u32; let _2: usize; - let mut _3: bool; + let mut _3: usize; + let mut _4: bool; bb0: { StorageLive(_2); _2 = const 0_usize; - FakeRead(ForIndex, _1); - _3 = Lt(copy _2, const 1_usize); - assert(move _3, "index out of bounds: the length is {} but the index is {}", const 1_usize, copy _2) -> [success: bb1, unwind: bb2]; + _3 = Len(_1); + _4 = Lt(copy _2, copy _3); + assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind: bb2]; } bb1: { diff --git a/tests/mir-opt/issue_72181.main.built.after.mir b/tests/mir-opt/issue_72181.main.built.after.mir index 9f3803f5407..aade84a6dd2 100644 --- a/tests/mir-opt/issue_72181.main.built.after.mir +++ b/tests/mir-opt/issue_72181.main.built.after.mir @@ -7,7 +7,8 @@ fn main() -> () { let mut _4: Foo; let mut _5: u64; let _6: usize; - let mut _7: bool; + let mut _7: usize; + let mut _8: bool; scope 1 { let _2: [Foo; 2]; scope 2 { @@ -37,9 +38,9 @@ fn main() -> () { StorageLive(_5); StorageLive(_6); _6 = const 0_usize; - FakeRead(ForIndex, _2); - _7 = Lt(copy _6, const 2_usize); - assert(move _7, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _6) -> [success: bb3, unwind: bb5]; + _7 = Len(_2); + _8 = Lt(copy _6, copy _7); + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb3, unwind: bb5]; } bb2: { 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 94ba7082c66..c02bab3524b 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -7,16 +7,18 @@ let _2: &[T]; let _3: &[T; 3]; let _4: [T; 3]; - let mut _8: !; + let mut _5: usize; + let mut _6: bool; + let mut _10: !; scope 1 { debug v => _2; - let _5: &T; - let _6: &T; let _7: &T; + let _8: &T; + let _9: &T; scope 2 { - debug v1 => _5; - debug v2 => _6; - debug v3 => _7; + debug v1 => _7; + debug v2 => _8; + debug v3 => _9; } } @@ -25,23 +27,25 @@ _4 = [copy _1, copy _1, copy _1]; _3 = &_4; _2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit)); + nop; + nop; goto -> bb2; } bb1: { - _8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable; + _10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable; } bb2: { - StorageLive(_5); - _5 = &(*_2)[0 of 3]; - StorageLive(_6); - _6 = &(*_2)[1 of 3]; StorageLive(_7); - _7 = &(*_2)[2 of 3]; + _7 = &(*_2)[0 of 3]; + StorageLive(_8); + _8 = &(*_2)[1 of 3]; + StorageLive(_9); + _9 = &(*_2)[2 of 3]; + StorageDead(_9); + StorageDead(_8); StorageDead(_7); - StorageDead(_6); - StorageDead(_5); StorageDead(_4); return; } 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 0455b2c326e..49be042588c 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -7,16 +7,18 @@ let _2: &[T]; let _3: &[T; 3]; let _4: [T; 3]; - let mut _8: !; + let mut _5: usize; + let mut _6: bool; + let mut _10: !; scope 1 { debug v => _2; - let _5: &T; - let _6: &T; let _7: &T; + let _8: &T; + let _9: &T; scope 2 { - debug v1 => _5; - debug v2 => _6; - debug v3 => _7; + debug v1 => _7; + debug v2 => _8; + debug v3 => _9; } } @@ -25,23 +27,25 @@ _4 = [copy _1, copy _1, copy _1]; _3 = &_4; _2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit)); + nop; + nop; goto -> bb2; } bb1: { - _8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue; + _10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue; } bb2: { - StorageLive(_5); - _5 = &(*_2)[0 of 3]; - StorageLive(_6); - _6 = &(*_2)[1 of 3]; StorageLive(_7); - _7 = &(*_2)[2 of 3]; + _7 = &(*_2)[0 of 3]; + StorageLive(_8); + _8 = &(*_2)[1 of 3]; + StorageLive(_9); + _9 = &(*_2)[2 of 3]; + StorageDead(_9); + StorageDead(_8); StorageDead(_7); - StorageDead(_6); - StorageDead(_5); StorageDead(_4); return; } diff --git a/tests/mir-opt/issue_91633.foo.built.after.mir b/tests/mir-opt/issue_91633.foo.built.after.mir index bf65b5b4a8c..50fdf08375a 100644 --- a/tests/mir-opt/issue_91633.foo.built.after.mir +++ b/tests/mir-opt/issue_91633.foo.built.after.mir @@ -6,9 +6,8 @@ fn foo(_1: Box<[T]>) -> T { let _2: T; let mut _3: &T; let _4: usize; - let mut _5: *const [T]; - let mut _6: usize; - let mut _7: bool; + let mut _5: usize; + let mut _6: bool; scope 1 { debug f => _2; } @@ -18,10 +17,9 @@ fn foo(_1: Box<[T]>) -> T { StorageLive(_3); StorageLive(_4); _4 = const 0_usize; - _5 = &raw const (*_1); - _6 = PtrMetadata(move _5); - _7 = Lt(copy _4, copy _6); - assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _4) -> [success: bb1, unwind: bb5]; + _5 = Len((*_1)); + _6 = Lt(copy _4, copy _5); + assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, copy _4) -> [success: bb1, unwind: bb5]; } bb1: { diff --git a/tests/mir-opt/issue_91633.fun.built.after.mir b/tests/mir-opt/issue_91633.fun.built.after.mir index d2fc438d3e8..5b41b376719 100644 --- a/tests/mir-opt/issue_91633.fun.built.after.mir +++ b/tests/mir-opt/issue_91633.fun.built.after.mir @@ -15,7 +15,7 @@ fn fun(_1: &[T]) -> &T { StorageLive(_2); StorageLive(_3); _3 = const 0_usize; - _4 = PtrMetadata(copy _1); + _4 = Len((*_1)); _5 = Lt(copy _3, copy _4); assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind: bb2]; } diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff index 98c5e868046..f052c8f63dc 100644 --- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-abort.diff @@ -11,14 +11,16 @@ let mut _6: &[u8]; let mut _7: &[u8; N]; let _8: usize; - let mut _9: bool; + let mut _9: usize; + let mut _10: bool; bb0: { - StorageLive(_3); + nop; StorageLive(_4); _4 = copy _1; - StorageLive(_5); +- StorageLive(_5); ++ nop; StorageLive(_6); StorageLive(_7); _7 = &(*_2); @@ -38,13 +40,16 @@ } bb2: { - StorageDead(_5); +- StorageDead(_5); ++ nop; StorageDead(_4); StorageLive(_8); _8 = copy _1; -- _9 = Lt(copy _8, const N); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind unreachable]; -+ _9 = copy _3; +- _9 = Len((*_2)); +- _10 = Lt(copy _8, copy _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable]; ++ _9 = const N; ++ _10 = copy _3; + assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind unreachable]; } @@ -56,7 +61,8 @@ } bb4: { - StorageDead(_5); +- StorageDead(_5); ++ nop; StorageDead(_4); _0 = const 42_u8; goto -> bb5; diff --git a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff index 72c73137869..3299e300431 100644 --- a/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_bound.GVN.panic-unwind.diff @@ -11,14 +11,16 @@ let mut _6: &[u8]; let mut _7: &[u8; N]; let _8: usize; - let mut _9: bool; + let mut _9: usize; + let mut _10: bool; bb0: { - StorageLive(_3); + nop; StorageLive(_4); _4 = copy _1; - StorageLive(_5); +- StorageLive(_5); ++ nop; StorageLive(_6); StorageLive(_7); _7 = &(*_2); @@ -38,13 +40,16 @@ } bb2: { - StorageDead(_5); +- StorageDead(_5); ++ nop; StorageDead(_4); StorageLive(_8); _8 = copy _1; -- _9 = Lt(copy _8, const N); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind continue]; -+ _9 = copy _3; +- _9 = Len((*_2)); +- _10 = Lt(copy _8, copy _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue]; ++ _9 = const N; ++ _10 = copy _3; + assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind continue]; } @@ -56,7 +61,8 @@ } bb4: { - StorageDead(_5); +- StorageDead(_5); ++ nop; StorageDead(_4); _0 = const 42_u8; goto -> bb5; diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff index 9ffaf44c02b..329eb80b3c4 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-abort.diff @@ -11,16 +11,19 @@ let mut _6: &[u8]; let mut _7: &[u8; N]; let _8: usize; - let mut _9: bool; - let _10: usize; - let mut _11: bool; + let mut _9: usize; + let mut _10: bool; + let _11: usize; + let mut _12: usize; + let mut _13: bool; bb0: { - StorageLive(_3); + nop; StorageLive(_4); _4 = copy _1; - StorageLive(_5); +- StorageLive(_5); ++ nop; StorageLive(_6); StorageLive(_7); _7 = &(*_2); @@ -40,13 +43,16 @@ } bb2: { - StorageDead(_5); +- StorageDead(_5); ++ nop; StorageDead(_4); StorageLive(_8); _8 = copy _1; -- _9 = Lt(copy _8, const N); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind unreachable]; -+ _9 = copy _3; +- _9 = Len((*_2)); +- _10 = Lt(copy _8, copy _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind unreachable]; ++ _9 = const N; ++ _10 = copy _3; + assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind unreachable]; } @@ -58,20 +64,23 @@ } bb4: { - StorageDead(_5); +- StorageDead(_5); ++ nop; StorageDead(_4); - StorageLive(_10); - _10 = const 0_usize; -- _11 = Lt(copy _10, const N); -- assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, copy _10) -> [success: bb5, unwind unreachable]; -+ _11 = Lt(const 0_usize, const N); -+ assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind unreachable]; + StorageLive(_11); + _11 = const 0_usize; +- _12 = Len((*_2)); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind unreachable]; ++ _12 = const N; ++ _13 = Lt(const 0_usize, const N); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind unreachable]; } bb5: { -- (*_2)[_10] = const 42_u8; +- (*_2)[_11] = const 42_u8; + (*_2)[0 of 1] = const 42_u8; - StorageDead(_10); + StorageDead(_11); _0 = const 42_u8; goto -> bb6; } diff --git a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff index 08008e46335..ab007e133ec 100644 --- a/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_bound_mut.GVN.panic-unwind.diff @@ -11,16 +11,19 @@ let mut _6: &[u8]; let mut _7: &[u8; N]; let _8: usize; - let mut _9: bool; - let _10: usize; - let mut _11: bool; + let mut _9: usize; + let mut _10: bool; + let _11: usize; + let mut _12: usize; + let mut _13: bool; bb0: { - StorageLive(_3); + nop; StorageLive(_4); _4 = copy _1; - StorageLive(_5); +- StorageLive(_5); ++ nop; StorageLive(_6); StorageLive(_7); _7 = &(*_2); @@ -40,13 +43,16 @@ } bb2: { - StorageDead(_5); +- StorageDead(_5); ++ nop; StorageDead(_4); StorageLive(_8); _8 = copy _1; -- _9 = Lt(copy _8, const N); -- assert(move _9, "index out of bounds: the length is {} but the index is {}", const N, copy _8) -> [success: bb3, unwind continue]; -+ _9 = copy _3; +- _9 = Len((*_2)); +- _10 = Lt(copy _8, copy _9); +- assert(move _10, "index out of bounds: the length is {} but the index is {}", move _9, copy _8) -> [success: bb3, unwind continue]; ++ _9 = const N; ++ _10 = copy _3; + assert(copy _3, "index out of bounds: the length is {} but the index is {}", const N, copy _1) -> [success: bb3, unwind continue]; } @@ -58,20 +64,23 @@ } bb4: { - StorageDead(_5); +- StorageDead(_5); ++ nop; StorageDead(_4); - StorageLive(_10); - _10 = const 0_usize; -- _11 = Lt(copy _10, const N); -- assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, copy _10) -> [success: bb5, unwind continue]; -+ _11 = Lt(const 0_usize, const N); -+ assert(move _11, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind continue]; + StorageLive(_11); + _11 = const 0_usize; +- _12 = Len((*_2)); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb5, unwind continue]; ++ _12 = const N; ++ _13 = Lt(const 0_usize, const N); ++ assert(move _13, "index out of bounds: the length is {} but the index is {}", const N, const 0_usize) -> [success: bb5, unwind continue]; } bb5: { -- (*_2)[_10] = const 42_u8; +- (*_2)[_11] = const 42_u8; + (*_2)[0 of 1] = const 42_u8; - StorageDead(_10); + StorageDead(_11); _0 = const 42_u8; goto -> bb6; } diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff index 4b39e18d16c..20001f1248e 100644 --- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff +++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-abort.diff @@ -36,7 +36,7 @@ StorageDead(_4); StorageLive(_7); _7 = copy _1; - _8 = PtrMetadata(copy _2); + _8 = Len((*_2)); _9 = Lt(copy _7, copy _8); assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb3, unwind unreachable]; } diff --git a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff index f0d4afa21ae..ca8f92df5de 100644 --- a/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff +++ b/tests/mir-opt/lower_slice_len.bound.LowerSliceLenCalls.panic-unwind.diff @@ -36,7 +36,7 @@ StorageDead(_4); StorageLive(_7); _7 = copy _1; - _8 = PtrMetadata(copy _2); + _8 = Len((*_2)); _9 = Lt(copy _7, copy _8); assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, copy _7) -> [success: bb3, unwind continue]; } diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 35e44b2314a..7294302609a 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -27,19 +27,20 @@ fn main() -> () { let mut _0: (); let mut _1: [usize; ValTree(Leaf(0x00000003): usize)]; let _3: usize; - let mut _4: bool; - let mut _6: bool; - let _7: bool; - let mut _8: usize; - let _9: bool; + let mut _4: usize; + let mut _5: bool; + let mut _7: bool; + let _8: bool; + let mut _9: usize; + let _10: bool; scope 1 { debug v => _1; let _2: &'?3 usize; scope 2 { debug p => _2; - let _5: &'?4 usize; + let _6: &'?4 usize; scope 3 { - debug q => _5; + debug q => _6; } } } @@ -51,50 +52,50 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); _3 = const ConstValue(Scalar(0x00000000): usize); - FakeRead(ForIndex, _1); - _4 = Lt(copy _3, const ConstValue(Scalar(0x00000003): usize)); - assert(move _4, "index out of bounds: the length is {} but the index is {}", const ConstValue(Scalar(0x00000003): usize), copy _3) -> [success: bb1, unwind: bb7]; + _4 = Len(_1); + _5 = Lt(copy _3, copy _4); + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind: bb7]; } bb1: { _2 = &'?2 _1[_3]; FakeRead(ForLet(None), _2); - StorageLive(_5); - _5 = copy _2; - FakeRead(ForLet(None), _5); StorageLive(_6); - _6 = const ConstValue(Scalar(0x01): bool); - switchInt(move _6) -> [0: bb4, otherwise: bb2]; + _6 = copy _2; + FakeRead(ForLet(None), _6); + StorageLive(_7); + _7 = const ConstValue(Scalar(0x01): bool); + switchInt(move _7) -> [0: bb4, otherwise: bb2]; } bb2: { - StorageLive(_7); StorageLive(_8); - _8 = copy (*_5); - _7 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _8) -> [return: bb3, unwind: bb7]; + StorageLive(_9); + _9 = copy (*_6); + _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; } bb3: { + StorageDead(_9); StorageDead(_8); - StorageDead(_7); _0 = const ConstValue(ZeroSized: ()); goto -> bb6; } bb4: { - StorageLive(_9); - _9 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; + StorageLive(_10); + _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; } bb5: { - StorageDead(_9); + StorageDead(_10); _0 = const ConstValue(ZeroSized: ()); goto -> bb6; } bb6: { + StorageDead(_7); StorageDead(_6); - StorageDead(_5); StorageDead(_3); StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 6d415f42d06..85b89a013c4 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -27,19 +27,20 @@ fn main() -> () { let mut _0: (); let mut _1: [usize; ValTree(Leaf(0x0000000000000003): usize)]; let _3: usize; - let mut _4: bool; - let mut _6: bool; - let _7: bool; - let mut _8: usize; - let _9: bool; + let mut _4: usize; + let mut _5: bool; + let mut _7: bool; + let _8: bool; + let mut _9: usize; + let _10: bool; scope 1 { debug v => _1; let _2: &'?3 usize; scope 2 { debug p => _2; - let _5: &'?4 usize; + let _6: &'?4 usize; scope 3 { - debug q => _5; + debug q => _6; } } } @@ -51,50 +52,50 @@ fn main() -> () { StorageLive(_2); StorageLive(_3); _3 = const ConstValue(Scalar(0x0000000000000000): usize); - FakeRead(ForIndex, _1); - _4 = Lt(copy _3, const ConstValue(Scalar(0x0000000000000003): usize)); - assert(move _4, "index out of bounds: the length is {} but the index is {}", const ConstValue(Scalar(0x0000000000000003): usize), copy _3) -> [success: bb1, unwind: bb7]; + _4 = Len(_1); + _5 = Lt(copy _3, copy _4); + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, copy _3) -> [success: bb1, unwind: bb7]; } bb1: { _2 = &'?2 _1[_3]; FakeRead(ForLet(None), _2); - StorageLive(_5); - _5 = copy _2; - FakeRead(ForLet(None), _5); StorageLive(_6); - _6 = const ConstValue(Scalar(0x01): bool); - switchInt(move _6) -> [0: bb4, otherwise: bb2]; + _6 = copy _2; + FakeRead(ForLet(None), _6); + StorageLive(_7); + _7 = const ConstValue(Scalar(0x01): bool); + switchInt(move _7) -> [0: bb4, otherwise: bb2]; } bb2: { - StorageLive(_7); StorageLive(_8); - _8 = copy (*_5); - _7 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _8) -> [return: bb3, unwind: bb7]; + StorageLive(_9); + _9 = copy (*_6); + _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; } bb3: { + StorageDead(_9); StorageDead(_8); - StorageDead(_7); _0 = const ConstValue(ZeroSized: ()); goto -> bb6; } bb4: { - StorageLive(_9); - _9 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; + StorageLive(_10); + _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; } bb5: { - StorageDead(_9); + StorageDead(_10); _0 = const ConstValue(ZeroSized: ()); goto -> bb6; } bb6: { + StorageDead(_7); StorageDead(_6); - StorageDead(_5); StorageDead(_3); StorageDead(_2); StorageDead(_1); diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir index cff5b4c7243..1a1c8b4b942 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-abort.mir @@ -13,7 +13,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::<impl u16>::checked_add) { let mut _5: (u16, bool); let mut _6: bool; - scope 7 (inlined unlikely) { + scope 7 (inlined std::intrinsics::unlikely) { let _7: (); } } @@ -55,7 +55,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 { } bb3: { - _7 = cold_path() -> [return: bb4, unwind unreachable]; + _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { diff --git a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir index 6e0242a220d..e7e19af048a 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.step_forward.PreCodegen.after.panic-unwind.mir @@ -13,7 +13,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 { scope 6 (inlined core::num::<impl u16>::checked_add) { let mut _5: (u16, bool); let mut _6: bool; - scope 7 (inlined unlikely) { + scope 7 (inlined std::intrinsics::unlikely) { let _7: (); } } @@ -55,7 +55,7 @@ fn step_forward(_1: u16, _2: usize) -> u16 { } bb3: { - _7 = cold_path() -> [return: bb4, unwind unreachable]; + _7 = std::intrinsics::cold_path() -> [return: bb4, unwind unreachable]; } bb4: { diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff index 5b39e45806e..6575610727b 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff @@ -7,16 +7,17 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: bool; - let mut _8: u32; + let mut _6: usize; + let mut _7: bool; + let mut _9: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _7: u32; + let _8: u32; scope 3 { - debug z => _7; + debug z => _8; } } } @@ -37,9 +38,10 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; -- _6 = Lt(copy _5, const 6_usize); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable]; -+ _6 = const true; + _6 = const 6_usize; +- _7 = Lt(copy _5, copy _6); +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable]; ++ _7 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind unreachable]; } @@ -48,13 +50,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); - StorageLive(_7); StorageLive(_8); - _8 = const 42_u32; -- _7 = copy _8; -+ _7 = const 42_u32; + StorageLive(_9); + _9 = const 42_u32; +- _8 = copy _9; ++ _8 = const 42_u32; + StorageDead(_9); StorageDead(_8); - StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff index ea2742a6471..1a4ed5767fe 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff @@ -7,16 +7,17 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: bool; - let mut _8: u32; + let mut _6: usize; + let mut _7: bool; + let mut _9: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _7: u32; + let _8: u32; scope 3 { - debug z => _7; + debug z => _8; } } } @@ -37,9 +38,10 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; -- _6 = Lt(copy _5, const 6_usize); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue]; -+ _6 = const true; + _6 = const 6_usize; +- _7 = Lt(copy _5, copy _6); +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue]; ++ _7 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind continue]; } @@ -48,13 +50,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); - StorageLive(_7); StorageLive(_8); - _8 = const 42_u32; -- _7 = copy _8; -+ _7 = const 42_u32; + StorageLive(_9); + _9 = const 42_u32; +- _8 = copy _9; ++ _8 = const 42_u32; + StorageDead(_9); StorageDead(_8); - StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff index 5b39e45806e..6575610727b 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff @@ -7,16 +7,17 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: bool; - let mut _8: u32; + let mut _6: usize; + let mut _7: bool; + let mut _9: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _7: u32; + let _8: u32; scope 3 { - debug z => _7; + debug z => _8; } } } @@ -37,9 +38,10 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; -- _6 = Lt(copy _5, const 6_usize); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable]; -+ _6 = const true; + _6 = const 6_usize; +- _7 = Lt(copy _5, copy _6); +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable]; ++ _7 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind unreachable]; } @@ -48,13 +50,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); - StorageLive(_7); StorageLive(_8); - _8 = const 42_u32; -- _7 = copy _8; -+ _7 = const 42_u32; + StorageLive(_9); + _9 = const 42_u32; +- _8 = copy _9; ++ _8 = const 42_u32; + StorageDead(_9); StorageDead(_8); - StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff index ea2742a6471..1a4ed5767fe 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff @@ -7,16 +7,17 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: bool; - let mut _8: u32; + let mut _6: usize; + let mut _7: bool; + let mut _9: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _7: u32; + let _8: u32; scope 3 { - debug z => _7; + debug z => _8; } } } @@ -37,9 +38,10 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; -- _6 = Lt(copy _5, const 6_usize); -- assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue]; -+ _6 = const true; + _6 = const 6_usize; +- _7 = Lt(copy _5, copy _6); +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue]; ++ _7 = const true; + assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> [success: bb2, unwind continue]; } @@ -48,13 +50,13 @@ + _3 = const 3_i32; StorageDead(_5); StorageDead(_4); - StorageLive(_7); StorageLive(_8); - _8 = const 42_u32; -- _7 = copy _8; -+ _7 = const 42_u32; + StorageLive(_9); + _9 = const 42_u32; +- _8 = copy _9; ++ _8 = const 42_u32; + StorageDead(_9); StorageDead(_8); - StorageDead(_7); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff index f7fe08831b9..e2420a341e0 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff @@ -7,18 +7,19 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: bool; - let mut _8: Point; -+ let mut _9: u32; + let mut _6: usize; + let mut _7: bool; + let mut _9: Point; + let mut _10: u32; ++ let mut _11: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _7: u32; + let _8: u32; scope 3 { - debug z => _7; + debug z => _8; } } } @@ -36,30 +37,31 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = Lt(copy _5, const 6_usize); - assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable]; + _6 = const 6_usize; + _7 = Lt(copy _5, copy _6); + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable]; } bb2: { _3 = copy _4[_5]; StorageDead(_5); StorageDead(_4); - StorageLive(_7); -- StorageLive(_8); -- _8 = Point { x: const 12_u32, y: const 42_u32 }; -- _7 = copy (_8.1: u32); -- StorageDead(_8); -+ StorageLive(_9); + StorageLive(_8); +- StorageLive(_9); +- _9 = Point { x: const 12_u32, y: const 42_u32 }; +- _8 = copy (_9.1: u32); +- StorageDead(_9); + StorageLive(_10); ++ StorageLive(_11); + nop; -+ _9 = const 12_u32; -+ _10 = const 42_u32; ++ _10 = const 12_u32; ++ _11 = const 42_u32; + nop; -+ _7 = copy _10; -+ StorageDead(_9); ++ _8 = copy _11; + StorageDead(_10); ++ StorageDead(_11); + nop; - StorageDead(_7); + StorageDead(_8); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff index 6e36386bea6..a2fb3b979e6 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff @@ -7,18 +7,19 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: bool; - let mut _8: Point; -+ let mut _9: u32; + let mut _6: usize; + let mut _7: bool; + let mut _9: Point; + let mut _10: u32; ++ let mut _11: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _7: u32; + let _8: u32; scope 3 { - debug z => _7; + debug z => _8; } } } @@ -36,30 +37,31 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = Lt(copy _5, const 6_usize); - assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue]; + _6 = const 6_usize; + _7 = Lt(copy _5, copy _6); + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue]; } bb2: { _3 = copy _4[_5]; StorageDead(_5); StorageDead(_4); - StorageLive(_7); -- StorageLive(_8); -- _8 = Point { x: const 12_u32, y: const 42_u32 }; -- _7 = copy (_8.1: u32); -- StorageDead(_8); -+ StorageLive(_9); + StorageLive(_8); +- StorageLive(_9); +- _9 = Point { x: const 12_u32, y: const 42_u32 }; +- _8 = copy (_9.1: u32); +- StorageDead(_9); + StorageLive(_10); ++ StorageLive(_11); + nop; -+ _9 = const 12_u32; -+ _10 = const 42_u32; ++ _10 = const 12_u32; ++ _11 = const 42_u32; + nop; -+ _7 = copy _10; -+ StorageDead(_9); ++ _8 = copy _11; + StorageDead(_10); ++ StorageDead(_11); + nop; - StorageDead(_7); + StorageDead(_8); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff index f7fe08831b9..e2420a341e0 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff @@ -7,18 +7,19 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: bool; - let mut _8: Point; -+ let mut _9: u32; + let mut _6: usize; + let mut _7: bool; + let mut _9: Point; + let mut _10: u32; ++ let mut _11: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _7: u32; + let _8: u32; scope 3 { - debug z => _7; + debug z => _8; } } } @@ -36,30 +37,31 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = Lt(copy _5, const 6_usize); - assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind unreachable]; + _6 = const 6_usize; + _7 = Lt(copy _5, copy _6); + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind unreachable]; } bb2: { _3 = copy _4[_5]; StorageDead(_5); StorageDead(_4); - StorageLive(_7); -- StorageLive(_8); -- _8 = Point { x: const 12_u32, y: const 42_u32 }; -- _7 = copy (_8.1: u32); -- StorageDead(_8); -+ StorageLive(_9); + StorageLive(_8); +- StorageLive(_9); +- _9 = Point { x: const 12_u32, y: const 42_u32 }; +- _8 = copy (_9.1: u32); +- StorageDead(_9); + StorageLive(_10); ++ StorageLive(_11); + nop; -+ _9 = const 12_u32; -+ _10 = const 42_u32; ++ _10 = const 12_u32; ++ _11 = const 42_u32; + nop; -+ _7 = copy _10; -+ StorageDead(_9); ++ _8 = copy _11; + StorageDead(_10); ++ StorageDead(_11); + nop; - StorageDead(_7); + StorageDead(_8); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff index 6e36386bea6..a2fb3b979e6 100644 --- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff +++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff @@ -7,18 +7,19 @@ let mut _2: (i32, bool); let mut _4: [i32; 6]; let _5: usize; - let mut _6: bool; - let mut _8: Point; -+ let mut _9: u32; + let mut _6: usize; + let mut _7: bool; + let mut _9: Point; + let mut _10: u32; ++ let mut _11: u32; scope 1 { debug x => _1; let _3: i32; scope 2 { debug y => _3; - let _7: u32; + let _8: u32; scope 3 { - debug z => _7; + debug z => _8; } } } @@ -36,30 +37,31 @@ _4 = [const 0_i32, const 1_i32, const 2_i32, const 3_i32, const 4_i32, const 5_i32]; StorageLive(_5); _5 = const 3_usize; - _6 = Lt(copy _5, const 6_usize); - assert(move _6, "index out of bounds: the length is {} but the index is {}", const 6_usize, copy _5) -> [success: bb2, unwind continue]; + _6 = const 6_usize; + _7 = Lt(copy _5, copy _6); + assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, copy _5) -> [success: bb2, unwind continue]; } bb2: { _3 = copy _4[_5]; StorageDead(_5); StorageDead(_4); - StorageLive(_7); -- StorageLive(_8); -- _8 = Point { x: const 12_u32, y: const 42_u32 }; -- _7 = copy (_8.1: u32); -- StorageDead(_8); -+ StorageLive(_9); + StorageLive(_8); +- StorageLive(_9); +- _9 = Point { x: const 12_u32, y: const 42_u32 }; +- _8 = copy (_9.1: u32); +- StorageDead(_9); + StorageLive(_10); ++ StorageLive(_11); + nop; -+ _9 = const 12_u32; -+ _10 = const 42_u32; ++ _10 = const 12_u32; ++ _11 = const 42_u32; + nop; -+ _7 = copy _10; -+ StorageDead(_9); ++ _8 = copy _11; + StorageDead(_10); ++ StorageDead(_11); + nop; - StorageDead(_7); + StorageDead(_8); StorageDead(_3); StorageDead(_1); return; diff --git a/tests/mir-opt/pre-codegen/slice_index.rs b/tests/mir-opt/pre-codegen/slice_index.rs index 5dac535d195..574062d6c35 100644 --- a/tests/mir-opt/pre-codegen/slice_index.rs +++ b/tests/mir-opt/pre-codegen/slice_index.rs @@ -9,7 +9,7 @@ use std::ops::Range; // EMIT_MIR slice_index.slice_index_usize.PreCodegen.after.mir pub fn slice_index_usize(slice: &[u32], index: usize) -> u32 { // CHECK-LABEL: slice_index_usize - // CHECK: [[LEN:_[0-9]+]] = PtrMetadata(copy _1) + // CHECK: [[LEN:_[0-9]+]] = Len((*_1)) // CHECK: Lt(copy _2, copy [[LEN]]) // CHECK-NOT: precondition_check // CHECK: _0 = copy (*_1)[_2]; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir index 81e60b8ec2c..cc1034229fc 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-abort.mir @@ -8,7 +8,7 @@ fn slice_index_usize(_1: &[u32], _2: usize) -> u32 { let mut _4: bool; bb0: { - _3 = PtrMetadata(copy _1); + _3 = Len((*_1)); _4 = Lt(copy _2, copy _3); assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind unreachable]; } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir index c0fdc839608..358226fb529 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_usize.PreCodegen.after.panic-unwind.mir @@ -8,7 +8,7 @@ fn slice_index_usize(_1: &[u32], _2: usize) -> u32 { let mut _4: bool; bb0: { - _3 = PtrMetadata(copy _1); + _3 = Len((*_1)); _4 = Lt(copy _2, copy _3); assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, copy _2) -> [success: bb1, unwind continue]; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir index 151783969dd..ecac03ad0f9 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir @@ -7,19 +7,20 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let mut _3: usize; let mut _4: usize; let mut _9: std::option::Option<usize>; - let mut _11: bool; - let mut _13: &impl Fn(usize, &T); - let mut _14: (usize, &T); - let _15: (); + let mut _11: usize; + let mut _12: bool; + let mut _14: &impl Fn(usize, &T); + let mut _15: (usize, &T); + let _16: (); scope 1 { debug ((iter: std::ops::Range<usize>).0: usize) => _4; debug ((iter: std::ops::Range<usize>).1: usize) => _3; let _10: usize; scope 2 { debug i => _10; - let _12: &T; + let _13: &T; scope 3 { - debug x => _12; + debug x => _13; } } scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) { @@ -81,22 +82,23 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_6); StorageDead(_7); _10 = copy ((_9 as Some).0: usize); - _11 = Lt(copy _10, copy _3); - assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb6, unwind unreachable]; + _11 = Len((*_1)); + _12 = Lt(copy _10, copy _11); + assert(move _12, "index out of bounds: the length is {} but the index is {}", move _11, copy _10) -> [success: bb6, unwind unreachable]; } bb6: { - _12 = &(*_1)[_10]; - StorageLive(_13); - _13 = &_2; + _13 = &(*_1)[_10]; StorageLive(_14); - _14 = (copy _10, copy _12); - _15 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _13, move _14) -> [return: bb7, unwind unreachable]; + _14 = &_2; + StorageLive(_15); + _15 = (copy _10, copy _13); + _16 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _14, move _15) -> [return: bb7, unwind unreachable]; } bb7: { + StorageDead(_15); StorageDead(_14); - StorageDead(_13); StorageDead(_9); goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir index 006329dc20d..1032473b9b2 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir @@ -7,19 +7,20 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let mut _3: usize; let mut _4: usize; let mut _9: std::option::Option<usize>; - let mut _11: bool; - let mut _13: &impl Fn(usize, &T); - let mut _14: (usize, &T); - let _15: (); + let mut _11: usize; + let mut _12: bool; + let mut _14: &impl Fn(usize, &T); + let mut _15: (usize, &T); + let _16: (); scope 1 { debug ((iter: std::ops::Range<usize>).0: usize) => _4; debug ((iter: std::ops::Range<usize>).1: usize) => _3; let _10: usize; scope 2 { debug i => _10; - let _12: &T; + let _13: &T; scope 3 { - debug x => _12; + debug x => _13; } } scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) { @@ -81,22 +82,23 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { StorageDead(_6); StorageDead(_7); _10 = copy ((_9 as Some).0: usize); - _11 = Lt(copy _10, copy _3); - assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb6, unwind: bb8]; + _11 = Len((*_1)); + _12 = Lt(copy _10, copy _11); + assert(move _12, "index out of bounds: the length is {} but the index is {}", move _11, copy _10) -> [success: bb6, unwind: bb8]; } bb6: { - _12 = &(*_1)[_10]; - StorageLive(_13); - _13 = &_2; + _13 = &(*_1)[_10]; StorageLive(_14); - _14 = (copy _10, copy _12); - _15 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _13, move _14) -> [return: bb7, unwind: bb8]; + _14 = &_2; + StorageLive(_15); + _15 = (copy _10, copy _13); + _16 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _14, move _15) -> [return: bb7, unwind: bb8]; } bb7: { + StorageDead(_15); StorageDead(_14); - StorageDead(_13); StorageDead(_9); goto -> bb1; } diff --git a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff index e9eea69377f..05ad9dbf3cc 100644 --- a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff @@ -92,7 +92,7 @@ StorageDead(_7); - StorageDead(_6); - StorageLive(_10); - StorageLive(_11); +- StorageLive(_11); - StorageLive(_12); StorageLive(_13); _26 = const debuginfo::promoted[0]; @@ -105,8 +105,9 @@ bb5: { StorageDead(_15); StorageDead(_13); - _11 = &(*_12); - _16 = PtrMetadata(copy _11); +- _11 = &(*_12); +- _16 = Len((*_11)); ++ _16 = Len((*_12)); _17 = const 3_usize; _18 = Ge(move _16, move _17); switchInt(move _18) -> [0: bb7, otherwise: bb6]; @@ -136,7 +137,7 @@ bb8: { - StorageDead(_12); - StorageDead(_11); +- StorageDead(_11); - StorageDead(_10); StorageLive(_22); StorageLive(_23); diff --git a/tests/run-make/cat-and-grep-sanity-check/Makefile b/tests/run-make/cat-and-grep-sanity-check/Makefile deleted file mode 100644 index 8ee69c0a0de..00000000000 --- a/tests/run-make/cat-and-grep-sanity-check/Makefile +++ /dev/null @@ -1,50 +0,0 @@ -# grep in run-make tests was partially replaced with a custom script, CGREP. This tests that CGREP does its job correctly. -# See https://github.com/rust-lang/rust/commit/ab788a2ee175c7560f0ca58bbc183ecfd57d2f7a -# FIXME(Oneirical): Note that this test will likely become useless after the port to rmake.rs tests (see https://github.com/rust-lang/rust/issues/121876) - -include ../tools.mk - -all: - echo a | $(CGREP) a - ! echo b | $(CGREP) a - echo xyz | $(CGREP) x y z - ! echo abc | $(CGREP) b c d - printf "x\ny\nz" | $(CGREP) x y z - - echo AbCd | $(CGREP) -i a b C D - ! echo AbCd | $(CGREP) a b C D - - true | $(CGREP) -v nothing - ! echo nothing | $(CGREP) -v nothing - ! echo xyz | $(CGREP) -v w x y - ! echo xyz | $(CGREP) -v x y z - echo xyz | $(CGREP) -v a b c - - ! echo 'foo bar baz' | $(CGREP) 'foo baz' - echo 'foo bar baz' | $(CGREP) foo baz - echo 'x a `b` c y z' | $(CGREP) 'a `b` c' - - echo baaac | $(CGREP) -e 'ba*c' - echo bc | $(CGREP) -e 'ba*c' - ! echo aaac | $(CGREP) -e 'ba*c' - - echo aaa | $(CGREP) -e 'a+' - ! echo bbb | $(CGREP) -e 'a+' - - echo abc | $(CGREP) -e 'a|e|i|o|u' - ! echo fgh | $(CGREP) -e 'a|e|i|o|u' - echo abc | $(CGREP) -e '[aeiou]' - ! echo fgh | $(CGREP) -e '[aeiou]' - ! echo abc | $(CGREP) -e '[^aeiou]{3}' - echo fgh | $(CGREP) -e '[^aeiou]{3}' - echo ab cd ef gh | $(CGREP) -e '\bcd\b' - ! echo abcdefgh | $(CGREP) -e '\bcd\b' - echo xyz | $(CGREP) -e '...' - ! echo xy | $(CGREP) -e '...' - ! echo xyz | $(CGREP) -e '\.\.\.' - echo ... | $(CGREP) -e '\.\.\.' - - echo foo bar baz | $(CGREP) -e 'foo.*baz' - ! echo foo bar baz | $(CGREP) -ve 'foo.*baz' - ! echo foo bar baz | $(CGREP) -e 'baz.*foo' - echo foo bar baz | $(CGREP) -ve 'baz.*foo' diff --git a/tests/run-make/crate-circular-deps-link/c.rs b/tests/run-make/crate-circular-deps-link/c.rs index 9d72657aa59..cfe00a2a347 100644 --- a/tests/run-make/crate-circular-deps-link/c.rs +++ b/tests/run-make/crate-circular-deps-link/c.rs @@ -1,5 +1,5 @@ #![crate_type = "bin"] -#![feature(start)] +#![no_main] #![no_std] extern crate a; @@ -24,8 +24,8 @@ unsafe impl GlobalAlloc for Allocator { #[global_allocator] static ALLOCATOR: Allocator = Allocator; -#[start] -fn main(argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { let mut v = Vec::new(); for i in 0..argc { v.push(i); diff --git a/tests/run-make/fmt-write-bloat/main.rs b/tests/run-make/fmt-write-bloat/main.rs index 6f206d6515a..b50461c0a02 100644 --- a/tests/run-make/fmt-write-bloat/main.rs +++ b/tests/run-make/fmt-write-bloat/main.rs @@ -1,5 +1,5 @@ #![feature(lang_items)] -#![feature(start)] +#![no_main] #![no_std] use core::fmt; @@ -17,8 +17,8 @@ impl fmt::Write for Dummy { } } -#[start] -fn main(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { let _ = writeln!(Dummy, "Hello World"); 0 } diff --git a/tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu/rmake.rs b/tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu/rmake.rs new file mode 100644 index 00000000000..0134457c5c2 --- /dev/null +++ b/tests/run-make/glibc-symbols-x86_64-unknown-linux-gnu/rmake.rs @@ -0,0 +1,112 @@ +// Check that the compiler toolchain (rustc) that we distribute is not using newer glibc +// symbols than a specified minimum. +// This test should only be executed on an extracted dist archive or in a dist-* CI job. + +//@ only-dist +//@ only-x86_64-unknown-linux-gnu +//@ ignore-cross-compile + +use std::path::{Path, PathBuf}; + +use run_make_support::{cmd, llvm_objdump, regex, rustc_path}; + +fn main() { + // This is the maximum glibc version that we are *permitted* to use for the + // x86_64-unknown-linux-gnu target. + // All glibc symbols used in the compiler must be lower or equal than this version. + // So that if a given machine only has glibc 2.17, it is able to run the compiler. + let max_supported = (2, 17, 99); + + let rustc = PathBuf::from(rustc_path()); + // Check symbols directly in rustc + check_symbols(&rustc, max_supported); + + // Find dynamic libraries referenced by rustc that come from our lib directory + let lib_path = rustc.parent().unwrap().parent().unwrap().join("lib"); + let dynamic_libs = find_dynamic_libs(&rustc) + .into_iter() + .filter_map(|path| path.canonicalize().ok()) + .filter(|lib| lib.starts_with(&lib_path)) + .collect::<Vec<_>>(); + for lib in dynamic_libs { + check_symbols(&lib, max_supported); + } +} + +#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)] +struct GlibcSymbol { + name: String, + version: (u32, u32, u32), +} + +fn find_dynamic_libs(path: &Path) -> Vec<PathBuf> { + cmd("ldd") + .arg(path) + .run() + .stdout_utf8() + .lines() + .filter_map(|line| { + let line = line.trim(); + let Some((_, line)) = line.split_once(" => ") else { + return None; + }; + line.split_ascii_whitespace().next().map(|path| PathBuf::from(path)) + }) + .collect() +} + +fn check_symbols(file: &Path, max_supported: (u32, u32, u32)) { + println!("Checking {}", file.display()); + let mut invalid: Vec<GlibcSymbol> = get_glibc_symbols(file) + .into_iter() + .filter(|symbol| symbol.version > max_supported) + .collect(); + if !invalid.is_empty() { + invalid.sort(); + panic!( + "Found invalid glibc symbols in {}:\n{}", + file.display(), + invalid + .into_iter() + .map(|symbol| format!( + "{} ({:?} higher than max allowed {:?})", + symbol.name, symbol.version, max_supported + )) + .collect::<Vec<_>>() + .join("\n") + ) + } +} + +fn get_glibc_symbols(file: &Path) -> Vec<GlibcSymbol> { + let regex = regex::Regex::new(r#"GLIBC_(\d)+\.(\d+)(:?\.(\d+))?"#).unwrap(); + + // FIXME(kobzol): llvm-objdump currently chokes on the BOLTed librustc_driver.so file. + // Use objdump instead, since it seems to work, and we only run this test in a specific + // CI environment anyway. + cmd("objdump") + .arg("--dynamic-syms") + .arg(file) + .run() + .stdout_utf8() + .lines() + .filter_map(|line| { + // Example line + // 0000000000000000 DF *UND* 0000000000000000 (GLIBC_2.2.5) sbrk + let mut parts = line.split(" ").collect::<Vec<_>>().into_iter().rev(); + let Some(name) = parts.next() else { + return None; + }; + let Some(lib) = parts.next() else { + return None; + }; + let Some(version) = regex.captures(lib) else { + return None; + }; + let major = version.get(1).and_then(|m| m.as_str().parse().ok()).unwrap_or(0); + let minor = version.get(2).and_then(|m| m.as_str().parse().ok()).unwrap_or(0); + let patch = version.get(3).and_then(|m| m.as_str().parse().ok()).unwrap_or(0); + Some(GlibcSymbol { version: (major, minor, patch), name: name.to_string() }) + }) + .collect() +} diff --git a/tests/run-make/jobserver-error/Makefile b/tests/run-make/jobserver-error/Makefile deleted file mode 100644 index 9f34970f96f..00000000000 --- a/tests/run-make/jobserver-error/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -include ../tools.mk - -# only-linux -# ignore-cross-compile - -# Test compiler behavior in case environment specifies wrong jobserver. -# Note that by default, the compiler uses file descriptors 0 (stdin), 1 (stdout), 2 (stderr), -# but also 3 and 4 for either end of the ctrl-c signal handler self-pipe. - -all: - bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=5,5" $(RUSTC)' 2>&1 | diff cannot_open_fd.stderr - - bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC) - 3</dev/null' 2>&1 | diff not_a_pipe.stderr - - -# This test randomly fails, see https://github.com/rust-lang/rust/issues/110321 -disabled: - bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC) - 3< <(cat /dev/null)' 2>&1 | diff poisoned_pipe.stderr - - diff --git a/tests/run-make/jobserver-error/cannot_open_fd.stderr b/tests/run-make/jobserver-error/cannot_open_fd.stderr index 9ac4c1c58f7..d075057b3d3 100644 --- a/tests/run-make/jobserver-error/cannot_open_fd.stderr +++ b/tests/run-make/jobserver-error/cannot_open_fd.stderr @@ -1,4 +1,4 @@ -warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--jobserver-auth=5,5"`: cannot open file descriptor 5 from the jobserver environment variable value: Bad file descriptor (os error 9) +warning: failed to connect to jobserver from environment variable `MAKEFLAGS="--jobserver-auth=1000,1000"`: cannot open file descriptor 1000 from the jobserver environment variable value: Bad file descriptor (os error 9) | = note: the build environment is likely misconfigured diff --git a/tests/run-make/jobserver-error/rmake.rs b/tests/run-make/jobserver-error/rmake.rs new file mode 100644 index 00000000000..14ee24c7148 --- /dev/null +++ b/tests/run-make/jobserver-error/rmake.rs @@ -0,0 +1,47 @@ +// ignore-tidy-linelength +//! If the environment variables contain an invalid `jobserver-auth`, this used to cause an ICE +//! until this was fixed in [do not panic on failure to acquire jobserver token +//! #109694](https://github.com/rust-lang/rust/pull/109694). +//! +//! Proper handling has been added, and this test checks that helpful warnings and errors are +//! printed instead in case of a wrong jobserver. See +//! <https://github.com/rust-lang/rust/issues/46981>. + +//@ only-linux +//@ ignore-cross-compile + +#![deny(warnings)] + +use run_make_support::{diff, rustc}; + +fn main() { + let out = rustc() + .stdin_buf(("fn main() {}").as_bytes()) + .env("MAKEFLAGS", "--jobserver-auth=1000,1000") + .run_fail() + .stderr_utf8(); + diff().expected_file("cannot_open_fd.stderr").actual_text("actual", out).run(); + + let out = rustc() + .stdin_buf(("fn main() {}").as_bytes()) + .input("-") + .env("MAKEFLAGS", "--jobserver-auth=3,3") + .set_aux_fd(3, std::fs::File::open("/dev/null").unwrap()) + .run() + .stderr_utf8(); + diff().expected_file("not_a_pipe.stderr").actual_text("actual", out).run(); + + // FIXME(#110321): the Makefile version had a disabled check: + // + // ```makefile + // bash -c 'echo "fn main() {}" | MAKEFLAGS="--jobserver-auth=3,3" $(RUSTC) - 3< <(cat /dev/null)' 2>&1 | diff poisoned_pipe.stderr - + // ``` + // + // > the jobserver helper thread launched here gets starved out and doesn't run, while the + // > coordinator thread continually processes work using the implicit jobserver token, never + // > yielding long enough for the jobserver helper to do its work (and process the error). + // + // but is not necessarily worth fixing as it might require changing coordinator behavior that + // might regress performance. See discussion at + // <https://github.com/rust-lang/rust/issues/110321#issuecomment-1636914956>. +} diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/main.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/main.rs new file mode 100644 index 00000000000..421eb4331b3 --- /dev/null +++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/main.rs @@ -0,0 +1,3 @@ +fn main() { + other::big_function(); +} diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/other.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/other.rs new file mode 100644 index 00000000000..a3ff578ebe4 --- /dev/null +++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/other.rs @@ -0,0 +1 @@ +proc::declare_big_function!(); diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/proc.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/proc.rs new file mode 100644 index 00000000000..59d17a9be59 --- /dev/null +++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/proc.rs @@ -0,0 +1,7 @@ +extern crate proc_macro; +use proc_macro::TokenStream; + +#[proc_macro] +pub fn declare_big_function(_input: TokenStream) -> TokenStream { + include_str!("./generated.rs").parse().unwrap() +} diff --git a/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs b/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs new file mode 100644 index 00000000000..2727effe818 --- /dev/null +++ b/tests/run-make/llvm-location-discriminator-limit-dummy-span/rmake.rs @@ -0,0 +1,65 @@ +//! Regression test for <https://github.com/rust-lang/rust/issues/135332>. +//! +//! We can't simply drop debuginfo location spans when LLVM's location discriminator value limit is +//! reached. Otherwise, with `-Z verify-llvm-ir` and fat LTO, LLVM will report a broken module for +//! +//! ```text +//! inlinable function call in a function with debug info must have a !dbg location +//! ``` + +//@ ignore-cross-compile +//@ needs-dynamic-linking +//@ only-nightly (requires unstable rustc flag) + +#![deny(warnings)] + +use run_make_support::{dynamic_lib_name, rfs, rust_lib_name, rustc}; + +// Synthesize a function that will have a large (`n`) number of functions +// MIR-inlined into it. When combined with a proc-macro, all of these inline +// callsites will have the same span, forcing rustc to use the DWARF +// discriminator to distinguish between them. LLVM's capacity to store that +// discriminator is not infinite (currently it allocates 12 bits for a +// maximum value of 4096) so if this function gets big enough rustc's error +// handling path will be exercised. +fn generate_program(n: u32) -> String { + let mut program = String::from("pub type BigType = Vec<Vec<String>>;\n\n"); + program.push_str("pub fn big_function() -> BigType {\n"); + program.push_str(" vec![\n"); + for i in 1..=n { + program.push_str(&format!("vec![\"string{}\".to_owned()],\n", i)); + } + program.push_str(" ]\n"); + program.push_str("}\n"); + program +} + +fn main() { + // The reported threshold is around 1366 (4096/3), but let's bump it to + // around 1500 to be less sensitive. + rfs::write("generated.rs", generate_program(1500)); + + rustc() + .input("proc.rs") + .crate_type("proc-macro") + .edition("2021") + .arg("-Cdebuginfo=line-tables-only") + .run(); + rustc() + .extern_("proc", dynamic_lib_name("proc")) + .input("other.rs") + .crate_type("rlib") + .edition("2021") + .opt_level("3") + .arg("-Cdebuginfo=line-tables-only") + .run(); + rustc() + .extern_("other", rust_lib_name("other")) + .input("main.rs") + .edition("2021") + .opt_level("3") + .arg("-Cdebuginfo=line-tables-only") + .arg("-Clto=fat") + .arg("-Zverify-llvm-ir") + .run(); +} diff --git a/tests/run-make/no-alloc-shim/foo.rs b/tests/run-make/no-alloc-shim/foo.rs index a3daec3db39..42606961f8b 100644 --- a/tests/run-make/no-alloc-shim/foo.rs +++ b/tests/run-make/no-alloc-shim/foo.rs @@ -35,7 +35,7 @@ unsafe impl GlobalAlloc for Alloc { static __rust_no_alloc_shim_is_unstable: u8 = 0; #[no_mangle] -extern "C" fn main(_argc: usize, _argv: *const *const i8) -> i32 { +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const i8) -> i32 { unsafe { assert_eq!(alloc::alloc::alloc(Layout::new::<()>()), core::ptr::null_mut()); } diff --git a/tests/run-make/sepcomp-inlining/foo.rs b/tests/run-make/sepcomp-inlining/foo.rs index 2fe5f9cb726..9101ee691a4 100644 --- a/tests/run-make/sepcomp-inlining/foo.rs +++ b/tests/run-make/sepcomp-inlining/foo.rs @@ -1,4 +1,4 @@ -#![feature(start)] +#![crate_type = "lib"] #[inline] fn inlined() -> u32 { @@ -21,8 +21,7 @@ mod b { } } -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +pub fn start(_: isize, _: *const *const u8) -> isize { a::f(); b::f(); diff --git a/tests/rustdoc-gui/huge-collection-of-constants.goml b/tests/rustdoc-gui/huge-collection-of-constants.goml index 387aca6f66c..643f0f51ac1 100644 --- a/tests/rustdoc-gui/huge-collection-of-constants.goml +++ b/tests/rustdoc-gui/huge-collection-of-constants.goml @@ -3,7 +3,7 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/huge_amount_of_consts/index.html" compare-elements-position-near-false: ( - "//ul[@class='item-table']/li[last()-1]", - "//ul[@class='item-table']/li[last()-3]", + "//dl[@class='item-table']/dt[last()-1]", + "//dl[@class='item-table']/dt[last()-3]", {"y": 12}, ) diff --git a/tests/rustdoc-gui/item-name-wrap.goml b/tests/rustdoc-gui/item-name-wrap.goml index 825c16ac5b8..d4da5c2d609 100644 --- a/tests/rustdoc-gui/item-name-wrap.goml +++ b/tests/rustdoc-gui/item-name-wrap.goml @@ -3,21 +3,21 @@ go-to: "file://" + |DOC_PATH| + "/test_docs/short_docs/index.html" set-window-size: (1000, 600) // First we ensure that there is only one `item-table`... -assert-count: ("ul.item-table", 1) +assert-count: ("dl.item-table", 1) // And only two items in it. -assert-count: ("ul.item-table li", 2) +assert-count: ("dl.item-table dt", 2) // If they don't have the same height, then it means one of the two is on two lines whereas it // shouldn't! compare-elements-size: ( - ".item-table .item-name a[href='fn.mult_vec_num.html']", - ".item-table .item-name a[href='fn.subt_vec_num.html']", + ".item-table dt a[href='fn.mult_vec_num.html']", + ".item-table dt a[href='fn.subt_vec_num.html']", ["height"], ) // We also check that the `item-table` is taking the full width. compare-elements-size: ( "#functions", - "ul.item-table", + "dl.item-table", ["width"], ) diff --git a/tests/rustdoc-gui/item-summary-table.goml b/tests/rustdoc-gui/item-summary-table.goml index 89306030329..7c0dfce3062 100644 --- a/tests/rustdoc-gui/item-summary-table.goml +++ b/tests/rustdoc-gui/item-summary-table.goml @@ -1,6 +1,6 @@ // This test ensures that <table> elements aren't display in items summary. go-to: "file://" + |DOC_PATH| + "/lib2/summary_table/index.html" // We check that we picked the right item first. -assert-text: (".item-table .item-name", "Foo") +assert-text: (".item-table dt", "Foo") // Then we check that its summary is empty. -assert-false: ".item-table .desc" +assert-false: ".item-table dd" diff --git a/tests/rustdoc-gui/label-next-to-symbol.goml b/tests/rustdoc-gui/label-next-to-symbol.goml index a8363f29dd5..7960dac11b6 100644 --- a/tests/rustdoc-gui/label-next-to-symbol.goml +++ b/tests/rustdoc-gui/label-next-to-symbol.goml @@ -12,59 +12,59 @@ assert: (".stab.portability") // make sure that deprecated and portability have the right colors assert-css: ( - ".item-table .item-name .stab.deprecated", + ".item-table dt .stab.deprecated", { "background-color": "#fff5d6" }, ) assert-css: ( - ".item-table .item-name .stab.portability", + ".item-table dt .stab.portability", { "background-color": "#fff5d6" }, ) // table like view -assert-css: (".desc.docblock-short", { "padding-left": "0px" }) +assert-css: ("dd", { "padding-left": "0px" }) compare-elements-position-near: ( - "//*[@class='item-name']//a[normalize-space()='replaced_function']", - ".item-name .stab.deprecated", + "//dt//a[normalize-space()='replaced_function']", + "dt .stab.deprecated", {"y": 2}, ) // "Unix" part is on second line compare-elements-position-false: ( - ".item-name .stab.deprecated", - ".item-name .stab.portability", + "dt .stab.deprecated", + "dt .stab.portability", ["y"], ) // Ensure no wrap compare-elements-position: ( - "//*[@class='item-name']//a[normalize-space()='replaced_function']/..", - "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']", + "//dt//a[normalize-space()='replaced_function']/..", + "//dd[normalize-space()='a thing with a label']", ["y"], ) // Mobile view set-window-size: (600, 600) // staggered layout with 2em spacing -assert-css: (".desc.docblock-short", { "padding-left": "32px" }) +assert-css: ("dd", { "padding-left": "32px" }) compare-elements-position-near: ( - "//*[@class='item-name']//a[normalize-space()='replaced_function']", - ".item-name .stab.deprecated", + "//dt//a[normalize-space()='replaced_function']", + "dt .stab.deprecated", {"y": 2}, ) compare-elements-position: ( - ".item-name .stab.deprecated", - ".item-name .stab.portability", + "dt .stab.deprecated", + "dt .stab.portability", ["y"], ) // Ensure wrap compare-elements-position-false: ( - "//*[@class='item-name']//a[normalize-space()='replaced_function']/..", - "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']", + "//dt//a[normalize-space()='replaced_function']/..", + "//dd[normalize-space()='a thing with a label']", ["y"], ) compare-elements-position-false: ( - ".item-name .stab.deprecated", - "//*[@class='desc docblock-short'][normalize-space()='a thing with a label']", + "dt .stab.deprecated", + "//dd[normalize-space()='a thing with a label']", ["y"], ) diff --git a/tests/rustdoc-gui/links-color.goml b/tests/rustdoc-gui/links-color.goml index 8d26b826479..f11920cdd8c 100644 --- a/tests/rustdoc-gui/links-color.goml +++ b/tests/rustdoc-gui/links-color.goml @@ -37,9 +37,9 @@ define-function: ( }, ALL, ) - move-cursor-to: ".desc a[href='long_code_block_link/index.html']" + move-cursor-to: "dd a[href='long_code_block_link/index.html']" assert-css: ( - ".desc a[href='long_code_block_link/index.html']", + "dd a[href='long_code_block_link/index.html']", {"text-decoration": "underline solid " + |mod|}, ) }, diff --git a/tests/rustdoc-gui/module-items-font.goml b/tests/rustdoc-gui/module-items-font.goml index 54c8131c3b9..0e6dd81c05b 100644 --- a/tests/rustdoc-gui/module-items-font.goml +++ b/tests/rustdoc-gui/module-items-font.goml @@ -1,67 +1,67 @@ // This test checks that the correct font is used on module items (in index.html pages). go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" assert-css: ( - ".item-table .item-name > a", + ".item-table dt > a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ALL, ) assert-css: ( - ".item-table .docblock-short", + ".item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ALL, ) // modules assert-css: ( - "#modules + .item-table .item-name a", + "#modules + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#modules + .item-table .desc.docblock-short", + "#modules + .item-table ", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // structs assert-css: ( - "#structs + .item-table .item-name a", + "#structs + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#structs + .item-table .desc.docblock-short", + "#structs + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // enums assert-css: ( - "#enums + .item-table .item-name a", + "#enums + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#enums + .item-table .desc.docblock-short", + "#enums + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // traits assert-css: ( - "#traits + .item-table .item-name a", + "#traits + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#traits + .item-table .desc.docblock-short", + "#traits + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // functions assert-css: ( - "#functions + .item-table .item-name a", + "#functions + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#functions + .item-table .desc.docblock-short", + "#functions + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) // keywords assert-css: ( - "#keywords + .item-table .item-name a", + "#keywords + .item-table dt a", {"font-family": '"Fira Sans", Arial, NanumBarunGothic, sans-serif'}, ) assert-css: ( - "#keywords + .item-table .desc.docblock-short", + "#keywords + .item-table dd", {"font-family": '"Source Serif 4", NanumBarunGothic, serif'}, ) diff --git a/tests/rustdoc-gui/sidebar.goml b/tests/rustdoc-gui/sidebar.goml index bb7453fdeac..38160cc49d0 100644 --- a/tests/rustdoc-gui/sidebar.goml +++ b/tests/rustdoc-gui/sidebar.goml @@ -65,8 +65,8 @@ assert-text: (".sidebar-elems section ul > li:nth-child(8)", "Functions") assert-text: (".sidebar-elems section ul > li:nth-child(9)", "Type Aliases") assert-text: (".sidebar-elems section ul > li:nth-child(10)", "Unions") assert-text: (".sidebar-elems section ul > li:nth-child(11)", "Keywords") -assert-text: ("#structs + .item-table .item-name > a", "Foo") -click: "#structs + .item-table .item-name > a" +assert-text: ("#structs + .item-table dt > a", "Foo") +click: "#structs + .item-table dt > a" // PAGE: struct.Foo.html assert-count: (".sidebar .sidebar-crate", 1) @@ -101,8 +101,8 @@ assert-text: (".sidebar-elems > section ul.block > li:nth-child(2)", "Structs") assert-text: (".sidebar-elems > section ul.block > li:nth-child(3)", "Traits") assert-text: (".sidebar-elems > section ul.block > li:nth-child(4)", "Functions") assert-text: (".sidebar-elems > section ul.block > li:nth-child(5)", "Type Aliases") -assert-text: ("#functions + .item-table .item-name > a", "foobar") -click: "#functions + .item-table .item-name > a" +assert-text: ("#functions + .item-table dt > a", "foobar") +click: "#functions + .item-table dt > a" // PAGE: fn.foobar.html // In items containing no items (like functions or constants) and in modules, we have no @@ -145,7 +145,7 @@ assert-text: (".sidebar-elems ul.block > li.current > a", "sub_sub_module") // We check that we don't have the crate list. assert-false: ".sidebar-elems .crate" assert-text: (".sidebar-elems > section ul > li:nth-child(1)", "Functions") -assert-text: ("#functions + .item-table .item-name > a", "foo") +assert-text: ("#functions + .item-table dt > a", "foo") // Links to trait implementations in the sidebar should not wrap even if they are long. go-to: "file://" + |DOC_PATH| + "/lib2/struct.HasALongTraitWithParams.html" diff --git a/tests/rustdoc-gui/unsafe-fn.goml b/tests/rustdoc-gui/unsafe-fn.goml index b8b2e1e27f5..b857afeff13 100644 --- a/tests/rustdoc-gui/unsafe-fn.goml +++ b/tests/rustdoc-gui/unsafe-fn.goml @@ -17,7 +17,7 @@ define-function: ( [theme, color], block { call-function: ("switch-theme", {"theme": |theme|}) - assert-css: (".item-name sup", {"color": |color|}) + assert-css: ("dt sup", {"color": |color|}) }, ) diff --git a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs index 571bc94e30f..db2ccefb0fb 100644 --- a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs +++ b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.rs @@ -1,4 +1,5 @@ //@ compile-flags:--test +//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ check-pass #![allow(rustdoc::invalid_codeblock_attributes)] diff --git a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout index e5c27bebbdb..7326c0a25a0 100644 --- a/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout +++ b/tests/rustdoc-ui/doctest/doctest-no-run-invalid-langstring-124577.stdout @@ -1,5 +1,5 @@ running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/tests/rustdoc-ui/invalid_const_in_lifetime_position.rs b/tests/rustdoc-ui/invalid_const_in_lifetime_position.rs index 07fc239a8f8..427c84679ba 100644 --- a/tests/rustdoc-ui/invalid_const_in_lifetime_position.rs +++ b/tests/rustdoc-ui/invalid_const_in_lifetime_position.rs @@ -8,4 +8,4 @@ fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {} //~| ERROR associated type takes 0 generic arguments but 1 generic argument //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments //~| ERROR associated type takes 0 generic arguments but 1 generic argument -//~| ERROR trait `X` cannot be made into an object +//~| ERROR trait `X` is not dyn compatible diff --git a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr index 0c3826c5665..180ba63927b 100644 --- a/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr +++ b/tests/rustdoc-ui/invalid_const_in_lifetime_position.stderr @@ -92,17 +92,18 @@ LL | type Y<'a>; | ^ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/invalid_const_in_lifetime_position.rs:4:20 | LL | fn f<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/invalid_const_in_lifetime_position.rs:2:10 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'a>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait diff --git a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs index 027574923c7..89b55beaea1 100644 --- a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs +++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.rs @@ -5,8 +5,8 @@ use std::ops::Index; pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) { //~^ expected 1 lifetime argument //~| expected 1 generic argument - //~| the trait `SVec` cannot be made into an object - //~| `SVec` cannot be made into an object + //~| the trait `SVec` is not dyn compatible + //~| `SVec` is not dyn compatible //~| missing generics for associated type `SVec::Item` //~| missing generics for associated type `SVec::Item` let _ = s; diff --git a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr index f9080bf0785..72d1a52f710 100644 --- a/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr +++ b/tests/rustdoc-ui/issues/ice-generic-type-alias-105742.stderr @@ -294,19 +294,20 @@ help: add missing generic argument LL | Output = <Self as SVec>::Item> as SVec>::Item<T>, | +++ -error[E0038]: the trait `SVec` cannot be made into an object - --> $DIR/ice-generic-type-alias-105742.rs:5:31 +error[E0038]: the trait `SVec` is not dyn compatible + --> $DIR/ice-generic-type-alias-105742.rs:5:35 | LL | pub fn next<'a, T>(s: &'a mut dyn SVec<Item = T, Output = T>) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `SVec` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/ice-generic-type-alias-105742.rs:15:17 | LL | pub trait SVec: Index< | ____________----__^ | | | - | | this trait cannot be made into an object... + | | this trait is not dyn compatible... LL | | <Self as SVec>::Item, ... | LL | |/ Output = <Index<<Self as SVec>::Item, diff --git a/tests/rustdoc/anonymous-reexport-108931.rs b/tests/rustdoc/anonymous-reexport-108931.rs index f4cc7f12396..b995c89b614 100644 --- a/tests/rustdoc/anonymous-reexport-108931.rs +++ b/tests/rustdoc/anonymous-reexport-108931.rs @@ -16,7 +16,7 @@ mod bar { //@ count - '//*[@id="main-content"]/h2' 2 //@ has - '//*[@id="main-content"]/h2' 'Re-exports' //@ has - '//*[@id="main-content"]/h2' 'Modules' -//@ has - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 'pub use foo::Foo as _;' -//@ has - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 'pub use bar::Bar as _;' +//@ has - '//*[@id="main-content"]//*[@class="item-table reexports"]/dt//code' 'pub use foo::Foo as _;' +//@ has - '//*[@id="main-content"]//*[@class="item-table reexports"]/dt//code' 'pub use bar::Bar as _;' pub use foo::Foo as _; pub use bar::Bar as _; diff --git a/tests/rustdoc/anonymous-reexport.rs b/tests/rustdoc/anonymous-reexport.rs index 8021008dc66..bf5fa93f953 100644 --- a/tests/rustdoc/anonymous-reexport.rs +++ b/tests/rustdoc/anonymous-reexport.rs @@ -9,7 +9,7 @@ //@ has - '//*[@id="main-content"]/h2' 'Structs' //@ has - '//*[@id="main-content"]/h2' 'Re-exports' // The 3 re-exports. -//@ count - '//*[@id="main-content"]//*[@class="item-table"]//li//code' 3 +//@ count - '//*[@id="main-content"]//*[@class="item-table reexports"]/dt//code' 3 // The public struct. //@ count - '//*[@id="main-content"]//a[@class="struct"]' 1 diff --git a/tests/rustdoc/attributes-inlining-108281.rs b/tests/rustdoc/attributes-inlining-108281.rs index ba6c570b59b..9dfaf1a6846 100644 --- a/tests/rustdoc/attributes-inlining-108281.rs +++ b/tests/rustdoc/attributes-inlining-108281.rs @@ -11,15 +11,15 @@ mod sub { pub fn public() {} } -//@ matches - '//*[@class="desc docblock-short"]' '^Displayed$' +//@ matches - '//dd' '^Displayed$' /// Displayed #[doc(inline)] pub use crate::bar as Bar; -//@ matches - '//*[@class="desc docblock-short"]' '^Hello\sDisplayed$' +//@ matches - '//dd' '^Hello\sDisplayed$' #[doc(inline)] /// Hello pub use crate::Bar as Bar2; -//@ matches - '//*[@class="desc docblock-short"]' '^Public$' +//@ matches - '//dd' '^Public$' /// Public pub use crate::sub::public as Public; diff --git a/tests/rustdoc/cfg_doc_reexport.rs b/tests/rustdoc/cfg_doc_reexport.rs index a07e4fe2f02..f8101e2a958 100644 --- a/tests/rustdoc/cfg_doc_reexport.rs +++ b/tests/rustdoc/cfg_doc_reexport.rs @@ -5,8 +5,8 @@ #![no_core] //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]/*[@class="stab portability"]' 'foobar' -//@ has - '//*[@class="item-name"]/*[@class="stab portability"]' 'bar' +//@ has - '//dt/*[@class="stab portability"]' 'foobar' +//@ has - '//dt/*[@class="stab portability"]' 'bar' #[doc(cfg(feature = "foobar"))] mod imp_priv { diff --git a/tests/rustdoc/deprecated.rs b/tests/rustdoc/deprecated.rs index b39da9b440a..a84657a3df5 100644 --- a/tests/rustdoc/deprecated.rs +++ b/tests/rustdoc/deprecated.rs @@ -1,6 +1,5 @@ -//@ has deprecated/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \ -// 'Deprecated' -//@ has - '//*[@class="desc docblock-short"]' 'Deprecated docs' +//@ has deprecated/index.html '//dt/span[@class="stab deprecated"]' 'Deprecated' +//@ has - '//dd' 'Deprecated docs' //@ has deprecated/struct.S.html '//*[@class="stab deprecated"]' \ // 'Deprecated since 1.0.0: text' @@ -8,7 +7,7 @@ #[deprecated(since = "1.0.0", note = "text")] pub struct S; -//@ matches deprecated/index.html '//*[@class="desc docblock-short"]' '^Docs' +//@ matches deprecated/index.html '//dd' '^Docs' /// Docs pub struct T; diff --git a/tests/rustdoc/display-hidden-items.rs b/tests/rustdoc/display-hidden-items.rs index d9f53435e46..40cd636e2fe 100644 --- a/tests/rustdoc/display-hidden-items.rs +++ b/tests/rustdoc/display-hidden-items.rs @@ -5,19 +5,19 @@ #![crate_name = "foo"] //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]/span[@title="Hidden item"]' '👻' +//@ has - '//dt/span[@title="Hidden item"]' '👻' //@ has - '//*[@id="reexport.hidden_reexport"]/code' '#[doc(hidden)] pub use hidden::inside_hidden as hidden_reexport;' #[doc(hidden)] pub use hidden::inside_hidden as hidden_reexport; -//@ has - '//*[@class="item-name"]/a[@class="trait"]' 'TraitHidden' +//@ has - '//dt/a[@class="trait"]' 'TraitHidden' //@ has 'foo/trait.TraitHidden.html' //@ has - '//code' '#[doc(hidden)] pub trait TraitHidden' #[doc(hidden)] pub trait TraitHidden {} -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="trait"]' 'Trait' +//@ has 'foo/index.html' '//dt/a[@class="trait"]' 'Trait' pub trait Trait { //@ has 'foo/trait.Trait.html' //@ has - '//*[@id="associatedconstant.BAR"]/*[@class="code-header"]' '#[doc(hidden)] const BAR: u32 = 0u32' @@ -29,7 +29,7 @@ pub trait Trait { fn foo() {} } -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="struct"]' 'Struct' +//@ has 'foo/index.html' '//dt/a[@class="struct"]' 'Struct' //@ has 'foo/struct.Struct.html' pub struct Struct { //@ has - '//*[@id="structfield.a"]/code' 'a: u32' @@ -50,7 +50,7 @@ impl Trait for Struct { //@ has - '//*[@id="impl-TraitHidden-for-Struct"]/*[@class="code-header"]' 'impl TraitHidden for Struct' impl TraitHidden for Struct {} -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="enum"]' 'HiddenEnum' +//@ has 'foo/index.html' '//dt/a[@class="enum"]' 'HiddenEnum' //@ has 'foo/enum.HiddenEnum.html' //@ has - '//code' '#[doc(hidden)] pub enum HiddenEnum' #[doc(hidden)] @@ -58,18 +58,18 @@ pub enum HiddenEnum { A, } -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="enum"]' 'Enum' +//@ has 'foo/index.html' '//dt/a[@class="enum"]' 'Enum' pub enum Enum { //@ has 'foo/enum.Enum.html' '//*[@id="variant.A"]/*[@class="code-header"]' 'A' #[doc(hidden)] A, } -//@ has 'foo/index.html' '//*[@class="item-name"]/a[@class="mod"]' 'hidden' +//@ has 'foo/index.html' '//dt/a[@class="mod"]' 'hidden' #[doc(hidden)] pub mod hidden { //@ has 'foo/hidden/index.html' - //@ has - '//*[@class="item-name"]/a[@class="fn"]' 'inside_hidden' + //@ has - '//dt/a[@class="fn"]' 'inside_hidden' //@ has 'foo/hidden/fn.inside_hidden.html' pub fn inside_hidden() {} } diff --git a/tests/rustdoc/doc-cfg.rs b/tests/rustdoc/doc-cfg.rs index 6c973b5666b..652c8419b4f 100644 --- a/tests/rustdoc/doc-cfg.rs +++ b/tests/rustdoc/doc-cfg.rs @@ -12,7 +12,7 @@ pub struct Portable; //@ has doc_cfg/unix_only/index.html \ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ // 'Available on Unix only.' -//@ matches - '//*[@class="item-name"]//*[@class="stab portability"]' '\AARM\Z' +//@ matches - '//dt//*[@class="stab portability"]' '\AARM\Z' //@ count - '//*[@class="stab portability"]' 2 #[doc(cfg(unix))] pub mod unix_only { @@ -42,7 +42,7 @@ pub mod unix_only { //@ has doc_cfg/wasi_only/index.html \ // '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ // 'Available on WASI only.' -//@ matches - '//*[@class="item-name"]//*[@class="stab portability"]' '\AWebAssembly\Z' +//@ matches - '//dt//*[@class="stab portability"]' '\AWebAssembly\Z' //@ count - '//*[@class="stab portability"]' 2 #[doc(cfg(target_os = "wasi"))] pub mod wasi_only { @@ -74,7 +74,7 @@ pub mod wasi_only { // the portability header is different on the module view versus the full view //@ has doc_cfg/index.html -//@ matches - '//*[@class="item-name"]//*[@class="stab portability"]' '\Aavx\Z' +//@ matches - '//dt//*[@class="stab portability"]' '\Aavx\Z' //@ has doc_cfg/fn.uses_target_feature.html //@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \ diff --git a/tests/rustdoc/doc-hidden-reexports-109449.rs b/tests/rustdoc/doc-hidden-reexports-109449.rs index cc3679f6196..8f195544120 100644 --- a/tests/rustdoc/doc-hidden-reexports-109449.rs +++ b/tests/rustdoc/doc-hidden-reexports-109449.rs @@ -26,7 +26,7 @@ pub mod single_reexport { //@ has 'foo/single_reexport/index.html' // First we check that we have 4 type aliases. - //@ count - '//*[@id="main-content"]/*[@class="item-table"]//code' 4 + //@ count - '//*[@id="main-content"]/*[@class="item-table reexports"]//code' 4 // Then we check that we have the correct link for each re-export. @@ -131,10 +131,10 @@ mod private { pub mod doc_hidden_reexport { //@ has 'foo/doc_hidden_reexport/index.html' // Ensure there is only one item in this page and that it's a struct. - //@ count - '//*[@class="item-name"]' 1 + //@ count - '//dt' 1 //@ has - '//a[@class="struct"]' 'Reexport' // Check that the `#[doc(hidden)]` re-export's attributes are not taken into account. - //@ has - '//*[@class="desc docblock-short"]' 'Visible. Original.' + //@ has - '//dd' 'Visible. Original.' /// Visible. pub use self::Bar3 as Reexport; /// Hidden. diff --git a/tests/rustdoc/double-hyphen-to-dash.rs b/tests/rustdoc/double-hyphen-to-dash.rs index 009de4faf41..c14acd065cd 100644 --- a/tests/rustdoc/double-hyphen-to-dash.rs +++ b/tests/rustdoc/double-hyphen-to-dash.rs @@ -2,7 +2,7 @@ #![crate_name = "foo"] -//@ has 'foo/index.html' '//*[@class="desc docblock-short"]' '–' +//@ has 'foo/index.html' '//dd' '–' //@ has 'foo/struct.Bar.html' '//*[@class="docblock"]' '–' /// -- diff --git a/tests/rustdoc/duplicate-cfg.rs b/tests/rustdoc/duplicate-cfg.rs index 87c089e9735..93f26ab944d 100644 --- a/tests/rustdoc/duplicate-cfg.rs +++ b/tests/rustdoc/duplicate-cfg.rs @@ -2,8 +2,8 @@ #![feature(doc_cfg)] //@ has 'foo/index.html' -//@ matches '-' '//*[@class="item-name"]//*[@class="stab portability"]' '^sync$' -//@ has '-' '//*[@class="item-name"]//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only' +//@ matches '-' '//dt//*[@class="stab portability"]' '^sync$' +//@ has '-' '//dt//*[@class="stab portability"]/@title' 'Available on crate feature `sync` only' //@ has 'foo/struct.Foo.html' //@ has '-' '//*[@class="stab portability"]' 'sync' diff --git a/tests/rustdoc/footnote-in-summary.rs b/tests/rustdoc/footnote-in-summary.rs index d69282f1041..2a9668a9963 100644 --- a/tests/rustdoc/footnote-in-summary.rs +++ b/tests/rustdoc/footnote-in-summary.rs @@ -4,8 +4,8 @@ #![crate_name = "foo"] //@ has 'foo/index.html' -//@ has - '//*[@class="desc docblock-short"]' 'hello bla' -//@ !has - '//*[@class="desc docblock-short"]/sup' '1' +//@ has - '//dd' 'hello bla' +//@ !has - '//dd/sup' '1' //@ has 'foo/struct.S.html' //@ has - '//*[@class="docblock"]//sup' '1' diff --git a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs index 2fa10f546d5..5b918e0ffd9 100644 --- a/tests/rustdoc/glob-reexport-attribute-merge-120487.rs +++ b/tests/rustdoc/glob-reexport-attribute-merge-120487.rs @@ -7,9 +7,9 @@ //@ has 'foo/index.html' // There are two items. -//@ count - '//*[@class="item-table"]//div[@class="item-name"]' 2 +//@ count - '//*[@class="item-table"]/dt' 2 // Only one of them should have an attribute. -//@ count - '//*[@class="item-table"]//div[@class="item-name"]/*[@class="stab portability"]' 1 +//@ count - '//*[@class="item-table"]/dt/*[@class="stab portability"]' 1 mod a { #[doc(cfg(not(feature = "a")))] diff --git a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs b/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs index 314b457c2ad..d0a2165ec8a 100644 --- a/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs +++ b/tests/rustdoc/glob-reexport-attribute-merge-doc-auto-cfg.rs @@ -6,9 +6,9 @@ //@ has 'foo/index.html' // There are two items. -//@ count - '//*[@class="item-table"]//div[@class="item-name"]' 2 +//@ count - '//*[@class="item-table"]/dt' 2 // Only one of them should have an attribute. -//@ count - '//*[@class="item-table"]//div[@class="item-name"]/*[@class="stab portability"]' 1 +//@ count - '//*[@class="item-table"]/dt/*[@class="stab portability"]' 1 mod a { #[cfg(not(feature = "a"))] diff --git a/tests/rustdoc/glob-shadowing-const.rs b/tests/rustdoc/glob-shadowing-const.rs index 1eb5596cd9c..fbc22dbccaa 100644 --- a/tests/rustdoc/glob-shadowing-const.rs +++ b/tests/rustdoc/glob-shadowing-const.rs @@ -15,6 +15,6 @@ mod sub4 { pub use sub4::inner::*; //@ has 'foo/index.html' -//@ has - '//div[@class="desc docblock-short"]' '1' -//@ !has - '//div[@class="desc docblock-short"]' '0' +//@ has - '//dd' '1' +//@ !has - '//dd' '0' fn main() { assert_eq!(X, 1); } diff --git a/tests/rustdoc/glob-shadowing.rs b/tests/rustdoc/glob-shadowing.rs index a051bd407d5..d9e9ead3f9a 100644 --- a/tests/rustdoc/glob-shadowing.rs +++ b/tests/rustdoc/glob-shadowing.rs @@ -1,17 +1,17 @@ //@ has 'glob_shadowing/index.html' -//@ count - '//div[@class="item-name"]' 6 -//@ !has - '//div[@class="desc docblock-short"]' 'sub1::describe' -//@ has - '//div[@class="desc docblock-short"]' 'sub2::describe' +//@ count - '//dt' 6 +//@ !has - '//dd' 'sub1::describe' +//@ has - '//dd' 'sub2::describe' -//@ !has - '//div[@class="desc docblock-short"]' 'sub1::describe2' +//@ !has - '//dd' 'sub1::describe2' -//@ !has - '//div[@class="desc docblock-short"]' 'sub1::prelude' -//@ has - '//div[@class="desc docblock-short"]' 'mod::prelude' +//@ !has - '//dd' 'sub1::prelude' +//@ has - '//dd' 'mod::prelude' -//@ has - '//div[@class="desc docblock-short"]' 'sub1::Foo (struct)' -//@ has - '//div[@class="desc docblock-short"]' 'mod::Foo (function)' +//@ has - '//dd' 'sub1::Foo (struct)' +//@ has - '//dd' 'mod::Foo (function)' -//@ has - '//div[@class="desc docblock-short"]' 'sub4::inner::X' +//@ has - '//dd' 'sub4::inner::X' //@ has 'glob_shadowing/fn.describe.html' //@ has - '//div[@class="docblock"]' 'sub2::describe' diff --git a/tests/rustdoc/impl-on-ty-alias-issue-119015.rs b/tests/rustdoc/impl-on-ty-alias-issue-119015.rs index cea0f5565a2..a514bc35bfc 100644 --- a/tests/rustdoc/impl-on-ty-alias-issue-119015.rs +++ b/tests/rustdoc/impl-on-ty-alias-issue-119015.rs @@ -2,8 +2,8 @@ //@ has 'foo/index.html' // There should be only `type A`. -//@ count - '//*[@class="item-table"]//*[@class="item-name"]' 1 -//@ has - '//*[@class="item-name"]/a[@href="type.A.html"]' 'A' +//@ count - '//*[@class="item-table"]//dt' 1 +//@ has - '//dt/a[@href="type.A.html"]' 'A' mod foo { pub struct S; diff --git a/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs b/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs index 752f3843eea..d27ecbad169 100644 --- a/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs +++ b/tests/rustdoc/inline-private-with-intermediate-doc-hidden.rs @@ -9,7 +9,7 @@ //@ count - '//*[@id="main-content"]/*[@class="section-header"]' 1 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Structs' //@ has - '//*[@id="main-content"]//a[@href="struct.Reexport.html"]' 'Reexport' -//@ has - '//*[@id="main-content"]//*[@class="desc docblock-short"]' 'Visible. Original.' +//@ has - '//*[@id="main-content"]//dd' 'Visible. Original.' mod private { /// Original. diff --git a/tests/rustdoc/inline_cross/inline_hidden.rs b/tests/rustdoc/inline_cross/inline_hidden.rs index 095cd2d3c55..49ca2db6a22 100644 --- a/tests/rustdoc/inline_cross/inline_hidden.rs +++ b/tests/rustdoc/inline_cross/inline_hidden.rs @@ -11,14 +11,14 @@ extern crate rustdoc_hidden; pub use rustdoc_hidden::Foo; // Even if the foreign item has `doc(hidden)`, we should be able to inline it. -//@ has - '//*[@class="item-name"]/a[@class="struct"]' 'Inlined' +//@ has - '//dt/a[@class="struct"]' 'Inlined' #[doc(inline)] pub use rustdoc_hidden::Foo as Inlined; // Even with this import, we should not see `Foo`. -//@ count - '//*[@class="item-name"]' 4 -//@ has - '//*[@class="item-name"]/a[@class="struct"]' 'Bar' -//@ has - '//*[@class="item-name"]/a[@class="fn"]' 'foo' +//@ count - '//dt' 4 +//@ has - '//dt/a[@class="struct"]' 'Bar' +//@ has - '//dt/a[@class="fn"]' 'foo' pub use rustdoc_hidden::*; //@ has inline_hidden/fn.foo.html diff --git a/tests/rustdoc/inline_cross/macros.rs b/tests/rustdoc/inline_cross/macros.rs index aab7a3650b1..57eec77899e 100644 --- a/tests/rustdoc/inline_cross/macros.rs +++ b/tests/rustdoc/inline_cross/macros.rs @@ -6,10 +6,8 @@ extern crate macros; -//@ has foo/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \ -// Deprecated -//@ has - '//*[@class="item-name"]/span[@class="stab unstable"]' \ -// Experimental +//@ has foo/index.html '//dt/span[@class="stab deprecated"]' Deprecated +//@ has - '//dt/span[@class="stab unstable"]' Experimental //@ has foo/macro.my_macro.html //@ has - '//*[@class="docblock"]' 'docs for my_macro' diff --git a/tests/rustdoc/internal.rs b/tests/rustdoc/internal.rs index e0bccefda1d..244e9138f2b 100644 --- a/tests/rustdoc/internal.rs +++ b/tests/rustdoc/internal.rs @@ -8,7 +8,7 @@ //@ !matches internal/index.html \ // '//*[@class="desc docblock-short"]/span[@class="stab internal"]' \ // '' -//@ matches - '//*[@class="desc docblock-short"]' 'Docs' +//@ matches - '//dd' 'Docs' //@ !has internal/struct.S.html '//*[@class="stab unstable"]' '' //@ !has internal/struct.S.html '//*[@class="stab internal"]' '' diff --git a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs b/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs index 06cb764423e..f0362f684ad 100644 --- a/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs +++ b/tests/rustdoc/intra-doc/module-scope-name-resolution-55364.rs @@ -32,8 +32,8 @@ pub mod subone { //@ has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.foo.html"]' 'foo' //@ has - '//section[@id="main-content"]/details/div[@class="docblock"]//a[@href="../fn.bar.html"]' 'bar' // Though there should be such links later -//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="item-name"]/a[@class="fn"][@href="fn.foo.html"]' 'foo' -//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="item-name"]/a[@class="fn"][@href="fn.bar.html"]' 'bar' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt/a[@class="fn"][@href="fn.foo.html"]' 'foo' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dt/a[@class="fn"][@href="fn.bar.html"]' 'bar' /// See either [foo] or [bar]. pub mod subtwo { @@ -71,8 +71,8 @@ pub mod subthree { // Next we go *deeper* - In order to ensure it's not just "this or parent" // we test `crate::` and a `super::super::...` chain //@ has foo/subfour/subfive/subsix/subseven/subeight/index.html -//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="desc docblock-short"]//a[@href="../../../../../subone/fn.foo.html"]' 'other foo' -//@ has - '//section[@id="main-content"]/ul[@class="item-table"]//div[@class="desc docblock-short"]//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd//a[@href="../../../../../subone/fn.foo.html"]' 'other foo' +//@ has - '//section[@id="main-content"]/dl[@class="item-table"]/dd//a[@href="../../../../../subtwo/fn.bar.html"]' 'other bar' pub mod subfour { pub mod subfive { pub mod subsix { diff --git a/tests/rustdoc/item-desc-list-at-start.item-table.html b/tests/rustdoc/item-desc-list-at-start.item-table.html index cff4f816529..89b4ac640f2 100644 --- a/tests/rustdoc/item-desc-list-at-start.item-table.html +++ b/tests/rustdoc/item-desc-list-at-start.item-table.html @@ -1 +1 @@ -<ul class="item-table"><li><div class="item-name"><a class="constant" href="constant.MY_CONSTANT.html" title="constant item_desc_list_at_start::MY_CONSTANT">MY_<wbr />CONSTANT</a></div><div class="desc docblock-short">Groups: <code>SamplePatternSGIS</code>, <code>SamplePatternEXT</code></div></li></ul> \ No newline at end of file +<dl class="item-table"><dt><a class="constant" href="constant.MY_CONSTANT.html" title="constant item_desc_list_at_start::MY_CONSTANT">MY_<wbr />CONSTANT</a></dt><dd>Groups: <code>SamplePatternSGIS</code>, <code>SamplePatternEXT</code></dd></dl> \ No newline at end of file diff --git a/tests/rustdoc/item-desc-list-at-start.rs b/tests/rustdoc/item-desc-list-at-start.rs index fbcc36066f1..7c2b31c9460 100644 --- a/tests/rustdoc/item-desc-list-at-start.rs +++ b/tests/rustdoc/item-desc-list-at-start.rs @@ -1,7 +1,8 @@ //@ has item_desc_list_at_start/index.html -//@ count - '//ul[@class="item-table"]/li/div/li' 0 -//@ count - '//ul[@class="item-table"]/li' 1 -//@ snapshot item-table - '//ul[@class="item-table"]' +//@ count - '//dl[@class="item-table"]/dd//ul' 0 +//@ count - '//dl[@class="item-table"]/dd//li' 0 +//@ count - '//dl[@class="item-table"]/dd' 1 +//@ snapshot item-table - '//dl[@class="item-table"]' // based on https://docs.rs/gl_constants/0.1.1/src/gl_constants/lib.rs.html#16 diff --git a/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs b/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs deleted file mode 100644 index 0d146a3c5cd..00000000000 --- a/tests/rustdoc/macro-rules-broken-intra-doc-106142.rs +++ /dev/null @@ -1,17 +0,0 @@ -// https://github.com/rust-lang/rust/issues/106142 -#![crate_name="foo"] - -//@ has 'foo/a/index.html' -//@ count 'foo/a/index.html' '//ul[@class="item-table"]//li//a' 1 - -#![allow(rustdoc::broken_intra_doc_links)] - -pub mod a { - /// [`m`] - pub fn f() {} - - #[macro_export] - macro_rules! m { - () => {}; - } -} diff --git a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs b/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs index 6d255ed6004..be32fcc7e4a 100644 --- a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs +++ b/tests/rustdoc/multiple-mods-w-same-name-doc-inline-83375.rs @@ -10,7 +10,7 @@ pub mod sub { } //@ count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1 -//@ count foo/prelude/index.html '//div[@class="item-row"]' 0 +//@ count foo/prelude/index.html '//ul[@class="item-table"]' 0 pub mod prelude {} #[doc(inline)] diff --git a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs b/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs index a59b48232a3..4b3b467382b 100644 --- a/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs +++ b/tests/rustdoc/multiple-mods-w-same-name-doc-inline-last-item-83375.rs @@ -13,5 +13,5 @@ pub mod sub { pub use sub::*; //@ count foo/index.html '//a[@class="mod"][@title="mod foo::prelude"]' 1 -//@ count foo/prelude/index.html '//div[@class="item-row"]' 0 +//@ count foo/prelude/index.html '//ul[@class="item-table"]' 0 pub mod prelude {} diff --git a/tests/rustdoc/nested-items-issue-111415.rs b/tests/rustdoc/nested-items-issue-111415.rs index a5cd3ca0b1a..79dc2b0378f 100644 --- a/tests/rustdoc/nested-items-issue-111415.rs +++ b/tests/rustdoc/nested-items-issue-111415.rs @@ -10,7 +10,7 @@ //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Functions' //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Traits' // Checking that there are only three items. -//@ count - '//*[@id="main-content"]//*[@class="item-name"]' 3 +//@ count - '//*[@id="main-content"]//dt' 3 //@ has - '//*[@id="main-content"]//a[@href="struct.Bar.html"]' 'Bar' //@ has - '//*[@id="main-content"]//a[@href="fn.foo.html"]' 'foo' //@ has - '//*[@id="main-content"]//a[@href="trait.Foo.html"]' 'Foo' diff --git a/tests/rustdoc/overlapping-reexport-105735-2.rs b/tests/rustdoc/overlapping-reexport-105735-2.rs index 9f823ec5923..fa43924ff4e 100644 --- a/tests/rustdoc/overlapping-reexport-105735-2.rs +++ b/tests/rustdoc/overlapping-reexport-105735-2.rs @@ -5,8 +5,8 @@ #![no_std] //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]/a[@class="type"]' 'AtomicU8' -//@ has - '//*[@class="item-name"]/a[@class="constant"]' 'AtomicU8' +//@ has - '//dt/a[@class="type"]' 'AtomicU8' +//@ has - '//dt/a[@class="constant"]' 'AtomicU8' // We also ensure we don't have another item displayed. //@ count - '//*[@id="main-content"]/*[@class="section-header"]' 2 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Type Aliases' diff --git a/tests/rustdoc/overlapping-reexport-105735.rs b/tests/rustdoc/overlapping-reexport-105735.rs index 2a2d0fa9830..d1b5c0b6749 100644 --- a/tests/rustdoc/overlapping-reexport-105735.rs +++ b/tests/rustdoc/overlapping-reexport-105735.rs @@ -5,8 +5,8 @@ #![no_std] //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]/a[@class="struct"]' 'AtomicU8' -//@ has - '//*[@class="item-name"]/a[@class="constant"]' 'AtomicU8' +//@ has - '//dt/a[@class="struct"]' 'AtomicU8' +//@ has - '//dt/a[@class="constant"]' 'AtomicU8' // We also ensure we don't have another item displayed. //@ count - '//*[@id="main-content"]/*[@class="section-header"]' 2 //@ has - '//*[@id="main-content"]/*[@class="section-header"]' 'Structs' diff --git a/tests/rustdoc/pub-use-root-path-95873.rs b/tests/rustdoc/pub-use-root-path-95873.rs index e3d5ee6e315..8e4fd9e8d50 100644 --- a/tests/rustdoc/pub-use-root-path-95873.rs +++ b/tests/rustdoc/pub-use-root-path-95873.rs @@ -1,5 +1,5 @@ // https://github.com/rust-lang/rust/issues/95873 #![crate_name = "foo"] -//@ has foo/index.html "//*[@class='item-name']" "pub use ::std as x;" +//@ has foo/index.html "//dt" "pub use ::std as x;" pub use ::std as x; diff --git a/tests/rustdoc/reexport-cfg.rs b/tests/rustdoc/reexport-cfg.rs index 7270da3d678..73b66824316 100644 --- a/tests/rustdoc/reexport-cfg.rs +++ b/tests/rustdoc/reexport-cfg.rs @@ -13,18 +13,18 @@ mod foo { } //@ has 'foo/index.html' -//@ has - '//*[@class="item-name"]' 'BabarNon-lie' +//@ has - '//dt' 'BabarNon-lie' #[cfg(not(feature = "lie"))] pub use crate::foo::Bar as Babar; -//@ has - '//*[@class="item-name"]' 'Babar2Non-cake' +//@ has - '//dt' 'Babar2Non-cake' #[doc(cfg(not(feature = "cake")))] pub use crate::foo::Bar2 as Babar2; -//@ has - '//*[@class="item-table"]/li' 'pub use crate::Babar as Elephant;Non-robot' +//@ has - '//*[@class="item-table reexports"]/dt' 'pub use crate::Babar as Elephant;Non-robot' #[cfg(not(feature = "robot"))] pub use crate::Babar as Elephant; -//@ has - '//*[@class="item-table"]/li' 'pub use crate::Babar2 as Elephant2;Non-cat' +//@ has - '//*[@class="item-table reexports"]/dt' 'pub use crate::Babar2 as Elephant2;Non-cat' #[doc(cfg(not(feature = "cat")))] pub use crate::Babar2 as Elephant2; diff --git a/tests/rustdoc/reexport-check.rs b/tests/rustdoc/reexport-check.rs index 0f4e203d1d3..fc10e3aadd0 100644 --- a/tests/rustdoc/reexport-check.rs +++ b/tests/rustdoc/reexport-check.rs @@ -8,13 +8,13 @@ extern crate reexport_check; #[allow(deprecated, deprecated_in_future)] pub use std::i32; //@ !has 'foo/index.html' '//code' 'pub use self::string::String;' -//@ has 'foo/index.html' '//div[@class="item-name"]' 'String' +//@ has 'foo/index.html' '//dt' 'String' pub use std::string::String; // i32 is deprecated, String is not //@ count 'foo/index.html' '//span[@class="stab deprecated"]' 1 -//@ has 'foo/index.html' '//div[@class="desc docblock-short"]' 'Docs in original' +//@ has 'foo/index.html' '//dd' 'Docs in original' // this is a no-op, but shows what happens if there's an attribute that isn't a doc-comment #[doc(inline)] pub use reexport_check::S; diff --git a/tests/rustdoc/reexport-doc-hidden-inside-private.rs b/tests/rustdoc/reexport-doc-hidden-inside-private.rs index fac928fc2a3..8e194ef74fb 100644 --- a/tests/rustdoc/reexport-doc-hidden-inside-private.rs +++ b/tests/rustdoc/reexport-doc-hidden-inside-private.rs @@ -12,5 +12,5 @@ mod private_module { //@ has - '//*[@id="reexport.Foo"]/code' 'pub use crate::private_module::Public as Foo;' pub use crate::private_module::Public as Foo; // Glob re-exports with no visible items should not be displayed. -//@ count - '//*[@class="item-table"]/li' 1 +//@ count - '//*[@class="item-table reexports"]/dt' 1 pub use crate::private_module::*; diff --git a/tests/rustdoc/reexport-of-reexport-108679.rs b/tests/rustdoc/reexport-of-reexport-108679.rs index 5c1b4bcbd83..0d2faf71d32 100644 --- a/tests/rustdoc/reexport-of-reexport-108679.rs +++ b/tests/rustdoc/reexport-of-reexport-108679.rs @@ -25,5 +25,6 @@ pub mod a { //@ has - '//*[@id="main-content"]//*[@id="reexport.A"]' 'pub use self::a::A;' //@ has - '//*[@id="main-content"]//*[@id="reexport.B"]' 'pub use self::a::B;' // Should only contain "Modules" and "Re-exports". -//@ count - '//*[@id="main-content"]//*[@class="item-table"]' 2 +//@ count - '//*[@id="main-content"]//*[@class="item-table"]' 1 +//@ count - '//*[@id="main-content"]//*[@class="item-table reexports"]' 1 pub use self::a::{A, B}; diff --git a/tests/rustdoc/reexport-trait-from-hidden-111064.rs b/tests/rustdoc/reexport-trait-from-hidden-111064.rs index 84ec818ef33..8b9ad7616ea 100644 --- a/tests/rustdoc/reexport-trait-from-hidden-111064.rs +++ b/tests/rustdoc/reexport-trait-from-hidden-111064.rs @@ -5,7 +5,7 @@ #![crate_name = "foo"] //@ has 'foo/index.html' -//@ has - '//*[@id="main-content"]//*[@class="item-name"]/a[@href="trait.Foo.html"]' 'Foo' +//@ has - '//*[@id="main-content"]//dt/a[@href="trait.Foo.html"]' 'Foo' //@ has 'foo/trait.Foo.html' //@ has - '//*[@id="main-content"]//*[@class="code-header"]' 'fn test()' diff --git a/tests/rustdoc/short-docblock.rs b/tests/rustdoc/short-docblock.rs index c80a5025ebe..fa0af85696a 100644 --- a/tests/rustdoc/short-docblock.rs +++ b/tests/rustdoc/short-docblock.rs @@ -1,7 +1,7 @@ #![crate_name = "foo"] -//@ has foo/index.html '//*[@class="desc docblock-short"]' 'fooo' -//@ !has foo/index.html '//*[@class="desc docblock-short"]/h1' 'fooo' +//@ has foo/index.html '//dd' 'fooo' +//@ !has foo/index.html '//dd//h1' 'fooo' //@ has foo/fn.foo.html '//h2[@id="fooo"]' 'fooo' //@ has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' '§' @@ -10,8 +10,8 @@ /// foo pub fn foo() {} -//@ has foo/index.html '//*[@class="desc docblock-short"]' 'mooood' -//@ !has foo/index.html '//*[@class="desc docblock-short"]/h2' 'mooood' +//@ has foo/index.html '//dd' 'mooood' +//@ !has foo/index.html '//dd//h2' 'mooood' //@ has foo/foo/index.html '//h3[@id="mooood"]' 'mooood' //@ has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' '§' @@ -20,8 +20,7 @@ pub fn foo() {} /// foo mod pub mod foo {} -//@ has foo/index.html '//*[@class="desc docblock-short"]/a[@href=\ -// "https://nougat.world"]/code' 'nougat' +//@ has foo/index.html '//dd/a[@href="https://nougat.world"]/code' 'nougat' /// [`nougat`](https://nougat.world) pub struct Bar; diff --git a/tests/rustdoc/sidebar/sidebar-items.rs b/tests/rustdoc/sidebar/sidebar-items.rs index 57c2eee91a9..6e13457796e 100644 --- a/tests/rustdoc/sidebar/sidebar-items.rs +++ b/tests/rustdoc/sidebar/sidebar-items.rs @@ -26,7 +26,7 @@ pub trait Foo { } //@ has foo/trait.DynCompatible.html -//@ !has - '//div[@class="sidebar-elems"]//h3/a[@href="#object-safety"]' '' +//@ !has - '//div[@class="sidebar-elems"]//h3/a[@href="#dyn-compatibility"]' '' pub trait DynCompatible { fn access(&self); } diff --git a/tests/rustdoc/stability.rs b/tests/rustdoc/stability.rs index 550eb0bc137..b74abb0e0ba 100644 --- a/tests/rustdoc/stability.rs +++ b/tests/rustdoc/stability.rs @@ -5,9 +5,9 @@ #![stable(feature = "core", since = "1.6.0")] //@ has stability/index.html -//@ has - '//ul[@class="item-table"]/li[1]//a' AaStable -//@ has - '//ul[@class="item-table"]/li[2]//a' ZzStable -//@ has - '//ul[@class="item-table"]/li[3]//a' Unstable +//@ has - '//dl[@class="item-table"]/dt[1]//a' AaStable +//@ has - '//dl[@class="item-table"]/dt[2]//a' ZzStable +//@ has - '//dl[@class="item-table"]/dt[3]//a' Unstable #[stable(feature = "rust2", since = "2.2.2")] pub struct AaStable; diff --git a/tests/rustdoc/staged-api-deprecated-unstable-32374.rs b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs index 556b6fb61ac..1021ce86df0 100644 --- a/tests/rustdoc/staged-api-deprecated-unstable-32374.rs +++ b/tests/rustdoc/staged-api-deprecated-unstable-32374.rs @@ -4,11 +4,9 @@ #![unstable(feature = "test", issue = "32374")] #![crate_name="issue_32374"] -//@ matches issue_32374/index.html '//*[@class="item-name"]/span[@class="stab deprecated"]' \ -// 'Deprecated' -//@ matches issue_32374/index.html '//*[@class="item-name"]/span[@class="stab unstable"]' \ -// 'Experimental' -//@ matches issue_32374/index.html '//*[@class="desc docblock-short"]/text()' 'Docs' +//@ matches issue_32374/index.html '//dt/span[@class="stab deprecated"]' 'Deprecated' +//@ matches issue_32374/index.html '//dt/span[@class="stab unstable"]' 'Experimental' +//@ matches issue_32374/index.html '//dd/text()' 'Docs' //@ has issue_32374/struct.T.html '//*[@class="stab deprecated"]/span' '👎' //@ has issue_32374/struct.T.html '//*[@class="stab deprecated"]/span' \ diff --git a/tests/rustdoc/summary-header-46377.rs b/tests/rustdoc/summary-header-46377.rs index 11445f0dad6..c84f3a65cfb 100644 --- a/tests/rustdoc/summary-header-46377.rs +++ b/tests/rustdoc/summary-header-46377.rs @@ -1,6 +1,6 @@ // https://github.com/rust-lang/rust/issues/46377 #![crate_name="foo"] -//@ has 'foo/index.html' '//*[@class="desc docblock-short"]' 'Check out this struct!' +//@ has 'foo/index.html' '//dd' 'Check out this struct!' /// # Check out this struct! pub struct SomeStruct; diff --git a/tests/ui-fulldeps/compiler-calls.rs b/tests/ui-fulldeps/compiler-calls.rs index 5fb47c87e50..d6148dfec43 100644 --- a/tests/ui-fulldeps/compiler-calls.rs +++ b/tests/ui-fulldeps/compiler-calls.rs @@ -25,7 +25,7 @@ fn main() { let mut count = 1; let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; rustc_driver::catch_fatal_errors(|| -> interface::Result<()> { - rustc_driver::RunCompiler::new(&args, &mut TestCalls { count: &mut count }).run(); + rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }); Ok(()) }) .ok(); diff --git a/tests/ui-fulldeps/obtain-borrowck.rs b/tests/ui-fulldeps/obtain-borrowck.rs index 8ea2ac61971..f8064c245a8 100644 --- a/tests/ui-fulldeps/obtain-borrowck.rs +++ b/tests/ui-fulldeps/obtain-borrowck.rs @@ -47,7 +47,7 @@ fn main() { rustc_args.push("-Zpolonius".to_owned()); let mut callbacks = CompilerCalls::default(); // Call the Rust compiler with our callbacks. - rustc_driver::RunCompiler::new(&rustc_args, &mut callbacks).run(); + rustc_driver::run_compiler(&rustc_args, &mut callbacks); Ok(()) }); std::process::exit(exit_code); diff --git a/tests/ui-fulldeps/run-compiler-twice.rs b/tests/ui-fulldeps/run-compiler-twice.rs index bcc235e58ed..f414c961627 100644 --- a/tests/ui-fulldeps/run-compiler-twice.rs +++ b/tests/ui-fulldeps/run-compiler-twice.rs @@ -72,7 +72,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf, linker: Option<&Path override_queries: None, make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), - using_internal_features: std::sync::Arc::default(), + using_internal_features: &rustc_driver::USING_INTERNAL_FEATURES, expanded_args: Default::default(), }; diff --git a/tests/ui/array-slice-vec/vec-macro-no-std.rs b/tests/ui/array-slice-vec/vec-macro-no-std.rs index 1b5ab536dcb..ea0df0bea71 100644 --- a/tests/ui/array-slice-vec/vec-macro-no-std.rs +++ b/tests/ui/array-slice-vec/vec-macro-no-std.rs @@ -1,21 +1,21 @@ //@ run-pass - //@ ignore-emscripten no no_std executables +//@ ignore-wasm different `main` convention -#![feature(lang_items, start, rustc_private)] #![no_std] +#![no_main] +// Import global allocator and panic handler. extern crate std as other; -#[macro_use] -extern crate alloc; +#[macro_use] extern crate alloc; use alloc::vec::Vec; // Issue #16806 -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { let x: Vec<u8> = vec![0, 1, 2]; match x.last() { Some(&2) => (), diff --git a/tests/ui/associated-consts/associated-const-in-trait.rs b/tests/ui/associated-consts/associated-const-in-trait.rs index 4e8143d5795..90ad596b23e 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.rs +++ b/tests/ui/associated-consts/associated-const-in-trait.rs @@ -5,9 +5,9 @@ trait Trait { } impl dyn Trait { - //~^ ERROR the trait `Trait` cannot be made into an object [E0038] + //~^ ERROR the trait `Trait` is not dyn compatible [E0038] const fn n() -> usize { Self::N } - //~^ ERROR the trait `Trait` cannot be made into an object [E0038] + //~^ ERROR the trait `Trait` is not dyn compatible [E0038] } fn main() {} diff --git a/tests/ui/associated-consts/associated-const-in-trait.stderr b/tests/ui/associated-consts/associated-const-in-trait.stderr index b40c1005797..107ceeaf113 100644 --- a/tests/ui/associated-consts/associated-const-in-trait.stderr +++ b/tests/ui/associated-consts/associated-const-in-trait.stderr @@ -1,29 +1,31 @@ -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/associated-const-in-trait.rs:7:6 | LL | impl dyn Trait { - | ^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/associated-const-in-trait.rs:4:11 | LL | trait Trait { - | ----- this trait cannot be made into an object... + | ----- this trait is not dyn compatible... LL | const N: usize; | ^ ...because it contains this associated `const` = help: consider moving `N` to another trait -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/associated-const-in-trait.rs:9:29 | LL | const fn n() -> usize { Self::N } - | ^^^^ `Trait` cannot be made into an object + | ^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/associated-const-in-trait.rs:4:11 | LL | trait Trait { - | ----- this trait cannot be made into an object... + | ----- this trait is not dyn compatible... LL | const N: usize; | ^ ...because it contains this associated `const` = help: consider moving `N` to another trait diff --git a/tests/ui/associated-item/issue-48027.rs b/tests/ui/associated-item/issue-48027.rs index d2b51184c99..715f3935107 100644 --- a/tests/ui/associated-item/issue-48027.rs +++ b/tests/ui/associated-item/issue-48027.rs @@ -3,6 +3,6 @@ trait Bar { fn return_n(&self) -> [u8; Bar::X]; //~ ERROR: E0790 } -impl dyn Bar {} //~ ERROR: the trait `Bar` cannot be made into an object +impl dyn Bar {} //~ ERROR: the trait `Bar` is not dyn compatible fn main() {} diff --git a/tests/ui/associated-item/issue-48027.stderr b/tests/ui/associated-item/issue-48027.stderr index 2883259ce2f..1baaefd7720 100644 --- a/tests/ui/associated-item/issue-48027.stderr +++ b/tests/ui/associated-item/issue-48027.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/issue-48027.rs:6:6 | LL | impl dyn Bar {} - | ^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-48027.rs:2:11 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | const X: usize; | ^ ...because it contains this associated `const` = help: consider moving `X` to another trait diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr index c5260adbed4..88db3611719 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -40,14 +40,14 @@ LL | type X = std::ops::Deref::Target; | help: use fully-qualified syntax | +LL | type X = <ByteStr as Deref>::Target; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type X = <ByteString as Deref>::Target; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | type X = <CString as Deref>::Target; | ~~~~~~~~~~~~~~~~~~~~~~~~~~ LL | type X = <IoSlice<'_> as Deref>::Target; | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | type X = <IoSliceMut<'_> as Deref>::Target; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -LL | type X = <OsString as Deref>::Target; - | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ and N other candidates error: aborting due to 5 previous errors diff --git a/tests/ui/async-await/async-closures/is-not-fn.stderr b/tests/ui/async-await/async-closures/is-not-fn.current.stderr index bc1d5e6e9d1..e7be1d5b10e 100644 --- a/tests/ui/async-await/async-closures/is-not-fn.stderr +++ b/tests/ui/async-await/async-closures/is-not-fn.current.stderr @@ -1,5 +1,5 @@ -error[E0271]: expected `{async closure@is-not-fn.rs:5:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:5:23: 5:25}` - --> $DIR/is-not-fn.rs:5:14 +error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` + --> $DIR/is-not-fn.rs:8:14 | LL | needs_fn(async || {}); | -------- ^^^^^^^^^^^ expected `()`, found `async` closure body @@ -7,9 +7,9 @@ LL | needs_fn(async || {}); | required by a bound introduced by this call | = note: expected unit type `()` - found `async` closure body `{async closure body@$DIR/is-not-fn.rs:5:23: 5:25}` + found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` note: required by a bound in `needs_fn` - --> $DIR/is-not-fn.rs:4:25 + --> $DIR/is-not-fn.rs:7:25 | LL | fn needs_fn(x: impl FnOnce()) {} | ^^^^^^^^ required by this bound in `needs_fn` diff --git a/tests/ui/async-await/async-closures/is-not-fn.next.stderr b/tests/ui/async-await/async-closures/is-not-fn.next.stderr new file mode 100644 index 00000000000..e7be1d5b10e --- /dev/null +++ b/tests/ui/async-await/async-closures/is-not-fn.next.stderr @@ -0,0 +1,19 @@ +error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` + --> $DIR/is-not-fn.rs:8:14 + | +LL | needs_fn(async || {}); + | -------- ^^^^^^^^^^^ expected `()`, found `async` closure body + | | + | required by a bound introduced by this call + | + = note: expected unit type `()` + found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}` +note: required by a bound in `needs_fn` + --> $DIR/is-not-fn.rs:7:25 + | +LL | fn needs_fn(x: impl FnOnce()) {} + | ^^^^^^^^ required by this bound in `needs_fn` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs index 4acaa5d9809..eacd07b7cdd 100644 --- a/tests/ui/async-await/async-closures/is-not-fn.rs +++ b/tests/ui/async-await/async-closures/is-not-fn.rs @@ -1,7 +1,10 @@ //@ edition:2021 +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver fn main() { fn needs_fn(x: impl FnOnce()) {} needs_fn(async || {}); - //~^ ERROR expected `{async closure@is-not-fn.rs:5:14}` to be a closure that returns `()` + //~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to be a closure that returns `()` } diff --git a/tests/ui/async-await/async-fn/dyn-pos.rs b/tests/ui/async-await/async-fn/dyn-pos.rs index d71af1bd53e..ab4685b07bb 100644 --- a/tests/ui/async-await/async-fn/dyn-pos.rs +++ b/tests/ui/async-await/async-fn/dyn-pos.rs @@ -1,6 +1,6 @@ //@ edition:2018 fn foo(x: &dyn AsyncFn()) {} -//~^ ERROR the trait `AsyncFnMut` cannot be made into an object +//~^ ERROR the trait `AsyncFnMut` is not dyn compatible fn main() {} diff --git a/tests/ui/async-await/async-fn/dyn-pos.stderr b/tests/ui/async-await/async-fn/dyn-pos.stderr index 0c901846671..f9d2a669477 100644 --- a/tests/ui/async-await/async-fn/dyn-pos.stderr +++ b/tests/ui/async-await/async-fn/dyn-pos.stderr @@ -1,17 +1,14 @@ -error[E0038]: the trait `AsyncFnMut` cannot be made into an object +error[E0038]: the trait `AsyncFnMut` is not dyn compatible --> $DIR/dyn-pos.rs:3:16 | LL | fn foo(x: &dyn AsyncFn()) {} - | ^^^^^^^^^ `AsyncFnMut` cannot be made into an object + | ^^^^^^^^^ `AsyncFnMut` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $SRC_DIR/core/src/ops/async_function.rs:LL:COL | - = note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture` - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead: - &F - &mut F - std::boxed::Box<F, A> + = note: the trait is not dyn compatible because it contains the generic associated type `CallRefFuture` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/coroutine-desc.stderr b/tests/ui/async-await/coroutine-desc.stderr index 01482a9cb1f..84a1a3166ad 100644 --- a/tests/ui/async-await/coroutine-desc.stderr +++ b/tests/ui/async-await/coroutine-desc.stderr @@ -30,7 +30,6 @@ LL | fun(one(), two()); | | expected all arguments to be this future type because they need to match the type of this parameter | arguments to this function are incorrect | - = help: consider `await`ing on both `Future`s = note: distinct uses of `impl Trait` result in different opaque types note: function defined here --> $DIR/coroutine-desc.rs:7:4 diff --git a/tests/ui/async-await/dont-suggest-missing-await.stderr b/tests/ui/async-await/dont-suggest-missing-await.stderr index 45a226c31f8..2ca52b2d5f5 100644 --- a/tests/ui/async-await/dont-suggest-missing-await.stderr +++ b/tests/ui/async-await/dont-suggest-missing-await.stderr @@ -6,20 +6,11 @@ LL | take_u32(x) | | | arguments to this function are incorrect | -note: calling an async function returns a future - --> $DIR/dont-suggest-missing-await.rs:14:18 - | -LL | take_u32(x) - | ^ note: function defined here --> $DIR/dont-suggest-missing-await.rs:5:4 | LL | fn take_u32(x: u32) {} | ^^^^^^^^ ------ -help: consider `await`ing on the `Future` - | -LL | take_u32(x.await) - | ++++++ error: aborting due to 1 previous error diff --git a/tests/ui/async-await/in-trait/dyn-compatibility.rs b/tests/ui/async-await/in-trait/dyn-compatibility.rs index 8174a803e79..c1b1ec79784 100644 --- a/tests/ui/async-await/in-trait/dyn-compatibility.rs +++ b/tests/ui/async-await/in-trait/dyn-compatibility.rs @@ -7,5 +7,5 @@ trait Foo { fn main() { let x: &dyn Foo = todo!(); - //~^ ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible } diff --git a/tests/ui/async-await/in-trait/dyn-compatibility.stderr b/tests/ui/async-await/in-trait/dyn-compatibility.stderr index 5cc3b6800dd..c6c406902f6 100644 --- a/tests/ui/async-await/in-trait/dyn-compatibility.stderr +++ b/tests/ui/async-await/in-trait/dyn-compatibility.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility.rs:9:12 | LL | let x: &dyn Foo = todo!(); - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-compatibility.rs:5:14 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | async fn foo(&self); | ^^^ ...because method `foo` is `async` = help: consider moving `foo` to another trait diff --git a/tests/ui/async-await/inference_var_self_argument.rs b/tests/ui/async-await/inference_var_self_argument.rs index 4d5ac4abb19..d03f2b5c50b 100644 --- a/tests/ui/async-await/inference_var_self_argument.rs +++ b/tests/ui/async-await/inference_var_self_argument.rs @@ -3,7 +3,7 @@ trait Foo { async fn foo(self: &dyn Foo) { - //~^ ERROR: `Foo` cannot be made into an object + //~^ ERROR: `Foo` is not dyn compatible //~| ERROR invalid `self` parameter type: `&dyn Foo` todo!() } diff --git a/tests/ui/async-await/inference_var_self_argument.stderr b/tests/ui/async-await/inference_var_self_argument.stderr index 7b7b3dbc757..a674fc0f3a5 100644 --- a/tests/ui/async-await/inference_var_self_argument.stderr +++ b/tests/ui/async-await/inference_var_self_argument.stderr @@ -7,17 +7,18 @@ LL | async fn foo(self: &dyn Foo) { = 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[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/inference_var_self_argument.rs:5:5 | LL | async fn foo(self: &dyn Foo) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/inference_var_self_argument.rs:5:14 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | async fn foo(self: &dyn Foo) { | ^^^ ...because method `foo` is `async` = help: consider moving `foo` to another trait diff --git a/tests/ui/async-await/issue-68523-start.rs b/tests/ui/async-await/issue-68523-start.rs deleted file mode 100644 index ee3baf4990c..00000000000 --- a/tests/ui/async-await/issue-68523-start.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ edition:2018 - -#![feature(start)] - -#[start] -pub async fn start(_: isize, _: *const *const u8) -> isize { -//~^ ERROR `#[start]` function is not allowed to be `async` - 0 -} diff --git a/tests/ui/async-await/issue-68523-start.stderr b/tests/ui/async-await/issue-68523-start.stderr deleted file mode 100644 index 5b76ab56e24..00000000000 --- a/tests/ui/async-await/issue-68523-start.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0752]: `#[start]` function is not allowed to be `async` - --> $DIR/issue-68523-start.rs:6:1 - | -LL | pub async fn start(_: isize, _: *const *const u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `#[start]` is not allowed to be `async` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0752`. diff --git a/tests/ui/attr-start.rs b/tests/ui/attr-start.rs deleted file mode 100644 index 232f50955b2..00000000000 --- a/tests/ui/attr-start.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ run-pass - -#![feature(start)] - -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { - return 0; -} diff --git a/tests/ui/borrowck/array-disjoint-borrows-issue-135671.rs b/tests/ui/borrowck/array-disjoint-borrows-issue-135671.rs new file mode 100644 index 00000000000..74b5cfcfb04 --- /dev/null +++ b/tests/ui/borrowck/array-disjoint-borrows-issue-135671.rs @@ -0,0 +1,30 @@ +// This is a regression test for issue #135671 where a MIR refactor about arrays and their lengths +// unexpectedly caused borrowck errors for disjoint borrows of array elements, for which we had no +// tests. This is a collection of a few code samples from that issue. + +//@ check-pass + +struct Test { + a: i32, + b: i32, +} + +fn one() { + let inputs: &mut [_] = &mut [Test { a: 0, b: 0 }]; + let a = &mut inputs[0].a; + let b = &mut inputs[0].b; + + *a = 0; + *b = 1; +} + +fn two() { + let slice = &mut [(0, 0)][..]; + std::mem::swap(&mut slice[0].0, &mut slice[0].1); +} + +fn three(a: &mut [(i32, i32)], i: usize, j: usize) -> (&mut i32, &mut i32) { + (&mut a[i].0, &mut a[j].1) +} + +fn main() {} diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.rs b/tests/ui/borrowck/borrowck-describe-lvalue.rs index f3a4b382fa8..cdcff69d6e5 100644 --- a/tests/ui/borrowck/borrowck-describe-lvalue.rs +++ b/tests/ui/borrowck/borrowck-describe-lvalue.rs @@ -231,6 +231,7 @@ fn main() { let x = &mut v; v[0].y; //~^ ERROR cannot use `v[_].y` because it was mutably borrowed + //~| ERROR cannot use `*v` because it was mutably borrowed drop(x); } // Field of constant index diff --git a/tests/ui/borrowck/borrowck-describe-lvalue.stderr b/tests/ui/borrowck/borrowck-describe-lvalue.stderr index 666a21808d8..11f2e42d42b 100644 --- a/tests/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/tests/ui/borrowck/borrowck-describe-lvalue.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:253:13 + --> $DIR/borrowck-describe-lvalue.rs:254:13 | LL | let y = &mut x; | ------ first mutable borrow occurs here @@ -9,7 +9,7 @@ LL | *y = 1; | ------ first borrow later used here error[E0499]: cannot borrow `x` as mutable more than once at a time - --> $DIR/borrowck-describe-lvalue.rs:263:20 + --> $DIR/borrowck-describe-lvalue.rs:264:20 | LL | let y = &mut x; | ------ first mutable borrow occurs here @@ -19,7 +19,7 @@ LL | *y = 1; | ------ first borrow later used here error: captured variable cannot escape `FnMut` closure body - --> $DIR/borrowck-describe-lvalue.rs:261:16 + --> $DIR/borrowck-describe-lvalue.rs:262:16 | LL | let mut x = 0; | ----- variable defined here @@ -300,6 +300,17 @@ LL | S { x: F { y: ref x0, .. }, .. } => LL | drop(x); | - mutable borrow later used here +error[E0503]: cannot use `*v` because it was mutably borrowed + --> $DIR/borrowck-describe-lvalue.rs:232:9 + | +LL | let x = &mut v; + | ------ `v` is borrowed here +LL | v[0].y; + | ^^^^ use of borrowed `v` +... +LL | drop(x); + | - borrow later used here + error[E0503]: cannot use `v[_].y` because it was mutably borrowed --> $DIR/borrowck-describe-lvalue.rs:232:9 | @@ -307,12 +318,12 @@ LL | let x = &mut v; | ------ `v` is borrowed here LL | v[0].y; | ^^^^^^ use of borrowed `v` -LL | +... LL | drop(x); | - borrow later used here error[E0502]: cannot borrow `v[..].x` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-describe-lvalue.rs:242:24 + --> $DIR/borrowck-describe-lvalue.rs:243:24 | LL | let x = &mut v; | ------ mutable borrow occurs here @@ -346,7 +357,7 @@ LL | drop(x); | - mutable borrow later used here error[E0382]: use of moved value: `x` - --> $DIR/borrowck-describe-lvalue.rs:273:22 + --> $DIR/borrowck-describe-lvalue.rs:274:22 | LL | drop(x); | - value moved here @@ -355,7 +366,7 @@ LL | drop(x); | = note: move occurs because `x` has type `Vec<i32>`, which does not implement the `Copy` trait -error: aborting due to 31 previous errors +error: aborting due to 32 previous errors Some errors have detailed explanations: E0382, E0499, E0502, E0503. For more information about an error, try `rustc --explain E0382`. diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs index 2d22c9a856f..3abc81e191e 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.rs @@ -12,7 +12,8 @@ fn arrays_1() { // c will capture `arr` completely, therefore another index into the // array can't be modified here arr[1] += 10; - //~^ ERROR: cannot use `arr[_]` because it was mutably borrowed + //~^ ERROR: cannot use `arr` because it was mutably borrowed + //~| ERROR: cannot use `arr[_]` because it was mutably borrowed c(); } @@ -54,7 +55,8 @@ fn arrays_4() { // c will capture `arr` completely, therefore we cannot borrow another index // into the array. println!("{}", arr[3]); - //~^ ERROR: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable + //~^ ERROR: cannot use `arr` because it was mutably borrowed + //~| ERROR: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable c(); } diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr index 97ecdfab820..9e5200ef34b 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/arrays.stderr @@ -1,3 +1,17 @@ +error[E0503]: cannot use `arr` because it was mutably borrowed + --> $DIR/arrays.rs:14:5 + | +LL | let mut c = || { + | -- `arr` is borrowed here +LL | arr[0] += 10; + | --- borrow occurs due to use of `arr` in closure +... +LL | arr[1] += 10; + | ^^^^^^ use of borrowed `arr` +... +LL | c(); + | - borrow later used here + error[E0503]: cannot use `arr[_]` because it was mutably borrowed --> $DIR/arrays.rs:14:5 | @@ -8,12 +22,12 @@ LL | arr[0] += 10; ... LL | arr[1] += 10; | ^^^^^^^^^^^^ use of borrowed `arr` -LL | +... LL | c(); | - borrow later used here error[E0506]: cannot assign to `arr[_]` because it is borrowed - --> $DIR/arrays.rs:28:5 + --> $DIR/arrays.rs:29:5 | LL | let c = || { | -- `arr[_]` is borrowed here @@ -27,7 +41,7 @@ LL | c(); | - borrow later used here error[E0506]: cannot assign to `arr[_]` because it is borrowed - --> $DIR/arrays.rs:42:5 + --> $DIR/arrays.rs:43:5 | LL | let c = || { | -- `arr[_]` is borrowed here @@ -40,8 +54,22 @@ LL | LL | c(); | - borrow later used here +error[E0503]: cannot use `arr` because it was mutably borrowed + --> $DIR/arrays.rs:57:20 + | +LL | let mut c = || { + | -- `arr` is borrowed here +LL | arr[1] += 10; + | --- borrow occurs due to use of `arr` in closure +... +LL | println!("{}", arr[3]); + | ^^^^^^ use of borrowed `arr` +... +LL | c(); + | - borrow later used here + error[E0502]: cannot borrow `arr[_]` as immutable because it is also borrowed as mutable - --> $DIR/arrays.rs:56:20 + --> $DIR/arrays.rs:57:20 | LL | let mut c = || { | -- mutable borrow occurs here @@ -57,7 +85,7 @@ LL | c(); = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0502]: cannot borrow `arr` as immutable because it is also borrowed as mutable - --> $DIR/arrays.rs:71:24 + --> $DIR/arrays.rs:73:24 | LL | let mut c = || { | -- mutable borrow occurs here @@ -70,7 +98,7 @@ LL | println!("{:#?}", &arr[3..2]); LL | c(); | - mutable borrow later used here -error: aborting due to 5 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0502, E0503, E0506. For more information about an error, try `rustc --explain E0502`. diff --git a/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr index 542be2dbc30..20257bbaf28 100644 --- a/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr +++ b/tests/ui/coherence/coherence-impl-trait-for-trait-dyn-compatible.stderr @@ -1,16 +1,17 @@ -error[E0038]: the trait `DynIncompatible` cannot be made into an object +error[E0038]: the trait `DynIncompatible` is not dyn compatible --> $DIR/coherence-impl-trait-for-trait-dyn-compatible.rs:7:26 | LL | impl DynIncompatible for dyn DynIncompatible { } - | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/coherence-impl-trait-for-trait-dyn-compatible.rs:6:45 | LL | trait DynIncompatible { fn eq(&self, other: Self); } | --------------- ^^^^ ...because method `eq` references the `Self` type in this parameter | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... = help: consider moving `eq` to another trait error[E0046]: not all trait items implemented, missing: `eq` diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr index 84281eb53c9..cd7f3a3c21d 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr @@ -1,28 +1,30 @@ -error[E0038]: the trait `ConstParamTy_` cannot be made into an object - --> $DIR/const_param_ty_dyn_compatibility.rs:6:12 +error[E0038]: the trait `ConstParamTy_` is not dyn compatible + --> $DIR/const_param_ty_dyn_compatibility.rs:6:16 | LL | fn foo(a: &dyn ConstParamTy_) {} - | ^^^^^^^^^^^^^^^^^ `ConstParamTy_` cannot be made into an object + | ^^^^^^^^^^^^^ `ConstParamTy_` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $SRC_DIR/core/src/cmp.rs:LL:COL | - = note: the trait cannot be made into an object because it uses `Self` as a type parameter + = note: the trait is not dyn compatible because it uses `Self` as a type parameter help: consider using an opaque type instead | LL | fn foo(a: &impl ConstParamTy_) {} | ~~~~ -error[E0038]: the trait `UnsizedConstParamTy` cannot be made into an object - --> $DIR/const_param_ty_dyn_compatibility.rs:9:12 +error[E0038]: the trait `UnsizedConstParamTy` is not dyn compatible + --> $DIR/const_param_ty_dyn_compatibility.rs:9:16 | LL | fn bar(a: &dyn UnsizedConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $SRC_DIR/core/src/cmp.rs:LL:COL | - = note: the trait cannot be made into an object because it uses `Self` as a type parameter + = note: the trait is not dyn compatible because it uses `Self` as a type parameter help: consider using an opaque type instead | LL | fn bar(a: &impl UnsizedConstParamTy) {} diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs index 1620e257667..9ab715d01f7 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.rs @@ -14,8 +14,8 @@ 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 use_dyn(v: &dyn Foo) { //~ERROR the trait `Foo` is not dyn compatible + v.test(); //~ERROR the trait `Foo` is not dyn compatible } fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr index d2017615e67..763bc626c9d 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-ret.stderr @@ -1,38 +1,40 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility-err-ret.rs:17:16 | LL | fn use_dyn(v: &dyn Foo) { - | ^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-compatibility-err-ret.rs:8:8 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn test(&self) -> [u8; bar::<Self>()]; | ^^^^ ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type | | | ...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 + = help: only type `()` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility-err-ret.rs:18:5 | LL | v.test(); - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-compatibility-err-ret.rs:8:8 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn test(&self) -> [u8; bar::<Self>()]; | ^^^^ ^^^^^^^^^^^^^^^^^^^ ...because method `test` references the `Self` type in its return type | | | ...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 + = help: only type `()` implements `Foo`; consider using it directly instead. error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs index b3bbb842638..a7b771cd4f8 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.rs @@ -13,9 +13,9 @@ impl Foo for () { } fn use_dyn(v: &dyn Foo) { - //~^ ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible v.test(); - //~^ ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible } fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr index 26ca2d4df5f..56678e4e9af 100644 --- a/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr +++ b/tests/ui/const-generics/generic_const_exprs/dyn-compatibility-err-where-bounds.stderr @@ -1,34 +1,36 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility-err-where-bounds.rs:15:16 | LL | fn use_dyn(v: &dyn Foo) { - | ^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... 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 + = help: only type `()` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility-err-where-bounds.rs:17:5 | LL | v.test(); - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-compatibility-err-where-bounds.rs:8:8 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... 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 + = help: only type `()` implements `Foo`; consider using it directly instead. error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.rs b/tests/ui/const-generics/generic_const_exprs/issue-102768.rs index f2ad7d7ce8b..882b27a418e 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-102768.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.rs @@ -13,7 +13,7 @@ const _: () = { //~| ERROR associated type takes 0 generic arguments but 1 generic argument //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments //~| ERROR associated type takes 0 generic arguments but 1 generic argument - //~| ERROR `X` cannot be made into an object + //~| ERROR `X` is not dyn compatible }; fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr index 9a75f372879..bd1811bd2cc 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-102768.stderr @@ -92,17 +92,18 @@ LL | type Y<'a>; | ^ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/issue-102768.rs:9:24 | LL | fn f2<'a>(arg: Box<dyn X<Y<1> = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-102768.rs:5:10 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'a>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait diff --git a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr index c851a8380f2..d90380396c1 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-80742.stderr @@ -6,6 +6,6 @@ Box<dyn Any> query stack during panic: #0 [eval_to_allocation_raw] const-evaluating + checking `<impl at $DIR/issue-80742.rs:26:1: 28:32>::{constant#0}` #1 [eval_to_valtree] evaluating type-level constant -end of query stack +... and 2 other queries... use `env RUST_BACKTRACE=1` to see the full query stack error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/index_array_bad_type.rs b/tests/ui/const-generics/issues/index_array_bad_type.rs deleted file mode 100644 index 41e4dba026c..00000000000 --- a/tests/ui/const-generics/issues/index_array_bad_type.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ check-fail -//@ compile-flags: -C opt-level=0 - -#![crate_type = "lib"] - -// This used to fail in the known-panics lint, as the MIR was ill-typed due to -// the length constant not actually having type usize. -// https://github.com/rust-lang/rust/issues/134352 - -pub struct BadStruct<const N: i64>(pub [u8; N]); -//~^ ERROR: the constant `N` is not of type `usize` - -pub fn bad_array_length_type(value: BadStruct<3>) -> u8 { - value.0[0] -} diff --git a/tests/ui/const-generics/issues/index_array_bad_type.stderr b/tests/ui/const-generics/issues/index_array_bad_type.stderr deleted file mode 100644 index e4417192150..00000000000 --- a/tests/ui/const-generics/issues/index_array_bad_type.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: the constant `N` is not of type `usize` - --> $DIR/index_array_bad_type.rs:10:40 - | -LL | pub struct BadStruct<const N: i64>(pub [u8; N]); - | ^^^^^^^ expected `usize`, found `i64` - -error: aborting due to 1 previous error - diff --git a/tests/ui/consts/const-unstable-intrinsic.stderr b/tests/ui/consts/const-unstable-intrinsic.stderr index 601c8647eee..308b02386f5 100644 --- a/tests/ui/consts/const-unstable-intrinsic.stderr +++ b/tests/ui/consts/const-unstable-intrinsic.stderr @@ -24,7 +24,10 @@ error: `size_of_val` is not yet stable as a const intrinsic LL | unstable_intrinsic::size_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: add `#![feature(unstable)]` to the crate attributes to enable +help: add `#![feature(unstable)]` to the crate attributes to enable + | +LL + #![feature(unstable)] + | error: `min_align_of_val` is not yet stable as a const intrinsic --> $DIR/const-unstable-intrinsic.rs:20:9 @@ -32,7 +35,10 @@ error: `min_align_of_val` is not yet stable as a const intrinsic LL | unstable_intrinsic::min_align_of_val(&x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: add `#![feature(unstable)]` to the crate attributes to enable +help: add `#![feature(unstable)]` to the crate attributes to enable + | +LL + #![feature(unstable)] + | error: const function that might be (indirectly) exposed to stable cannot use `#[feature(local)]` --> $DIR/const-unstable-intrinsic.rs:24:9 diff --git a/tests/ui/consts/issue-65348.rs b/tests/ui/consts/issue-65348.rs index 0d12da3926c..1443fcbe1c1 100644 --- a/tests/ui/consts/issue-65348.rs +++ b/tests/ui/consts/issue-65348.rs @@ -9,17 +9,15 @@ impl<T> Generic<T> { } pub const fn array<T>() -> &'static T { - #[expect(unconditional_panic)] + #[allow(unconditional_panic)] &Generic::<T>::ARRAY[0] } pub const fn newtype_array<T>() -> &'static T { - #[expect(unconditional_panic)] &Generic::<T>::NEWTYPE_ARRAY.0[0] } pub const fn array_field<T>() -> &'static T { - #[expect(unconditional_panic)] &(Generic::<T>::ARRAY_FIELD.0).1[0] } diff --git a/tests/ui/consts/too_generic_eval_ice.stderr b/tests/ui/consts/too_generic_eval_ice.stderr index b48be16a24c..3cc4377514a 100644 --- a/tests/ui/consts/too_generic_eval_ice.stderr +++ b/tests/ui/consts/too_generic_eval_ice.stderr @@ -32,13 +32,13 @@ LL | [5; Self::HOST_SIZE] == [6; 0] = help: the following other types implement trait `PartialEq<Rhs>`: `&[T]` implements `PartialEq<Vec<U, A>>` `&[T]` implements `PartialEq<[U; N]>` + `&[u8; N]` implements `PartialEq<ByteStr>` + `&[u8; N]` implements `PartialEq<ByteString>` + `&[u8]` implements `PartialEq<ByteStr>` + `&[u8]` implements `PartialEq<ByteString>` `&mut [T]` implements `PartialEq<Vec<U, A>>` `&mut [T]` implements `PartialEq<[U; N]>` - `[T; N]` implements `PartialEq<&[U]>` - `[T; N]` implements `PartialEq<&mut [U]>` - `[T; N]` implements `PartialEq<[U; N]>` - `[T; N]` implements `PartialEq<[U]>` - and 3 others + and 11 others error: aborting due to 4 previous errors diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs b/tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs new file mode 100644 index 00000000000..3a8d9c998cf --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_off.rs @@ -0,0 +1,29 @@ +//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g +//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=off +//@ check-pass + +//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm +//@[aarch64_gl] needs-llvm-components: aarch64 + +//@[i686_g] compile-flags: --target i686-pc-windows-gnu +//@[i686_g] needs-llvm-components: x86 + +//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm +//@[i686_gl] needs-llvm-components: x86 + +//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu +//@[i686_uwp_g] needs-llvm-components: x86 + +//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu +//@[x86_64_g] needs-llvm-components: x86 + +//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm +//@[x86_64_gl] needs-llvm-components: x86 + +//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu +//@[x86_64_uwp_g] needs-llvm-components: x86 + +#![feature(no_core)] + +#![no_core] +#![no_std] diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr new file mode 100644 index 00000000000..f3465e64976 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.aarch64_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr new file mode 100644 index 00000000000..f3465e64976 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr new file mode 100644 index 00000000000..f3465e64976 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr new file mode 100644 index 00000000000..f3465e64976 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.i686_uwp_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs new file mode 100644 index 00000000000..896bbac7d8e --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.rs @@ -0,0 +1,29 @@ +//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g +//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=packed +//@ error-pattern: error: `-Csplit-debuginfo=packed` is unstable on this platform + +//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm +//@[aarch64_gl] needs-llvm-components: aarch64 + +//@[i686_g] compile-flags: --target i686-pc-windows-gnu +//@[i686_g] needs-llvm-components: x86 + +//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm +//@[i686_gl] needs-llvm-components: x86 + +//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu +//@[i686_uwp_g] needs-llvm-components: x86 + +//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu +//@[x86_64_g] needs-llvm-components: x86 + +//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm +//@[x86_64_gl] needs-llvm-components: x86 + +//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu +//@[x86_64_uwp_g] needs-llvm-components: x86 + +#![feature(no_core)] + +#![no_core] +#![no_std] diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr new file mode 100644 index 00000000000..f3465e64976 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr new file mode 100644 index 00000000000..f3465e64976 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr new file mode 100644 index 00000000000..f3465e64976 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_packed.x86_64_uwp_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=packed` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr new file mode 100644 index 00000000000..0964e21b13b --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.aarch64_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr new file mode 100644 index 00000000000..0964e21b13b --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr new file mode 100644 index 00000000000..0964e21b13b --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr new file mode 100644 index 00000000000..0964e21b13b --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.i686_uwp_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs new file mode 100644 index 00000000000..54a88c91217 --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.rs @@ -0,0 +1,29 @@ +//@ revisions: aarch64_gl i686_g i686_gl i686_uwp_g x86_64_g x86_64_gl x86_64_uwp_g +//@ compile-flags: --crate-type cdylib -Csplit-debuginfo=unpacked +//@ error-pattern: error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +//@[aarch64_gl] compile-flags: --target aarch64-pc-windows-gnullvm +//@[aarch64_gl] needs-llvm-components: aarch64 + +//@[i686_g] compile-flags: --target i686-pc-windows-gnu +//@[i686_g] needs-llvm-components: x86 + +//@[i686_gl] compile-flags: --target i686-pc-windows-gnullvm +//@[i686_gl] needs-llvm-components: x86 + +//@[i686_uwp_g] compile-flags: --target i686-uwp-windows-gnu +//@[i686_uwp_g] needs-llvm-components: x86 + +//@[x86_64_g] compile-flags: --target x86_64-pc-windows-gnu +//@[x86_64_g] needs-llvm-components: x86 + +//@[x86_64_gl] compile-flags: --target x86_64-pc-windows-gnullvm +//@[x86_64_gl] needs-llvm-components: x86 + +//@[x86_64_uwp_g] compile-flags: --target x86_64-uwp-windows-gnu +//@[x86_64_uwp_g] needs-llvm-components: x86 + +#![feature(no_core)] + +#![no_core] +#![no_std] diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr new file mode 100644 index 00000000000..0964e21b13b --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr new file mode 100644 index 00000000000..0964e21b13b --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_gl.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr new file mode 100644 index 00000000000..0964e21b13b --- /dev/null +++ b/tests/ui/debuginfo/windows_gnu_split_debuginfo_unpacked.x86_64_uwp_g.stderr @@ -0,0 +1,4 @@ +error: `-Csplit-debuginfo=unpacked` is unstable on this platform + +error: aborting due to 1 previous error + diff --git a/tests/ui/deprecation/deprecation-lint.stderr b/tests/ui/deprecation/deprecation-lint.stderr index 2098073409d..95ae1b04d86 100644 --- a/tests/ui/deprecation/deprecation-lint.stderr +++ b/tests/ui/deprecation/deprecation-lint.stderr @@ -739,8 +739,11 @@ LL | _) error[E0451]: field `i` of struct `this_crate::nested::DeprecatedStruct` is private --> $DIR/deprecation-lint.rs:280:13 | +LL | let _ = nested::DeprecatedStruct { + | ------------------------ in this type +LL | LL | i: 0 - | ^^^^ private field + | ^ private field error: aborting due to 123 previous errors diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs index c9a097d3610..9cd32ffeb6d 100644 --- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs +++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.rs @@ -2,6 +2,6 @@ fn main() { let _: &Copy + 'static; //~ ERROR expected a path - //~^ ERROR cannot be made into an object + //~^ ERROR is not dyn compatible let _: &'static Copy + 'static; //~ ERROR expected a path } diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index 8ef0d178444..7994ddf11c3 100644 --- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -20,14 +20,15 @@ help: try adding parentheses LL | let _: &'static (Copy + 'static); | + + -error[E0038]: the trait `Copy` cannot be made into an object +error[E0038]: the trait `Copy` is not dyn compatible --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 | LL | let _: &Copy + 'static; - | ^^^^^ `Copy` cannot be made into an object + | ^^^^^ `Copy` is not dyn compatible | - = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "dyn-compatible" 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> + = note: the trait is not dyn compatible because it requires `Self: Sized` + = note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> error: aborting due to 3 previous errors diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed new file mode 100644 index 00000000000..78cf421cfbf --- /dev/null +++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed @@ -0,0 +1,575 @@ +// This tests various aspects of the drop order with a focus on: +// +// - The lifetime of temporaries with the `if let` construct (and with +// various similar constructs) and how these lifetimes were shortened +// for `if let` in Rust 2024. +// +// - The shortening of the lifetimes of temporaries in tail +// expressions in Rust 2024. +// +// - The behavior of `let` chains and how this behavior compares to +// nested `if let` expressions and chained `let .. else` statements. +// +// In the tests below, `Events` tracks a sequence of numbered events. +// Calling `e.mark(..)` logs a numbered event immediately. Calling +// `e.ok(..)` or `e.err(..)` returns an `Ok(_)` or `Err(_)` value, +// respectively, and logs the numbered event when that value is +// dropped. Calling `e.assert()` verifies that the correct number of +// events were logged and that they were logged in the correct order. + +//@ revisions: e2021 e2024 +//@ [e2021] edition: 2021 +//@ [e2021] run-rustfix +//@ [e2021] rustfix-only-machine-applicable +//@ [e2024] edition: 2024 +//@ run-pass + +#![feature(let_chains)] +#![cfg_attr(e2021, warn(rust_2024_compatibility))] + +fn t_bindings() { + let e = Events::new(); + _ = { + e.mark(1); + let _v = e.ok(8); + let _v = e.ok(2).is_ok(); + let _ = e.ok(3); + let Ok(_) = e.ok(4) else { unreachable!() }; + let Ok(_) = e.ok(5).as_ref() else { unreachable!() }; + let _v = e.ok(7); + e.mark(6); + }; + e.assert(8); +} + +fn t_tuples() { + let e = Events::new(); + _ = (e.ok(1), e.ok(4).is_ok(), e.ok(2), e.ok(3).is_ok()); + e.assert(4); +} + +fn t_arrays() { + let e = Events::new(); + trait Tr {} + impl<T> Tr for T {} + fn b<'a, T: 'a>(x: T) -> Box<dyn Tr + 'a> { + Box::new(x) + } + _ = [b(e.ok(1)), b(e.ok(4).is_ok()), b(e.ok(2)), b(e.ok(3).is_ok())]; + e.assert(4); +} + +fn t_fncalls() { + let e = Events::new(); + let f = |_, _, _, _| {}; + _ = f(e.ok(2), e.ok(4).is_ok(), e.ok(1), e.ok(3).is_ok()); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_tailexpr_bindings() { + let e = Events::new(); + _ = ({ + let _v = e.ok(2); + let _v = e.ok(1); + e.ok(5).is_ok() + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + }, e.mark(3), e.ok(4)); + e.assert(5); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_tailexpr_bindings() { + let e = Events::new(); + _ = ({ + let _v = e.ok(3); + let _v = e.ok(2); + e.ok(1).is_ok() + }, e.mark(4), e.ok(5)); + e.assert(5); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_tailexpr_tuples() { + let e = Events::new(); + _ = ({ + (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok()) + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + //[e2021]~| WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + }, e.mark(1), e.ok(4)); + e.assert(6); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_tailexpr_tuples() { + let e = Events::new(); + _ = ({ + (e.ok(4), e.ok(2).is_ok(), e.ok(5), e.ok(1).is_ok()) + }, e.mark(3), e.ok(6)); + e.assert(6); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_then() { + let e = Events::new(); + _ = (match e.ok(4).as_ref() { Ok(_) => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + } _ => {}}, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_then() { + let e = Events::new(); + _ = (if let Ok(_) = e.ok(2).as_ref() { + e.mark(1); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_else() { + let e = Events::new(); + _ = (match e.err(4).as_ref() { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + }}, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_else() { + let e = Events::new(); + _ = (if let Ok(_) = e.err(1).as_ref() {} else { + e.mark(2); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_match_then() { + let e = Events::new(); + _ = (match e.ok(4).as_ref() { + Ok(_) => e.mark(1), + _ => unreachable!(), + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_match_else() { + let e = Events::new(); + _ = (match e.err(4).as_ref() { + Ok(_) => unreachable!(), + _ => e.mark(1), + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_let_else_then() { + let e = Events::new(); + _ = ('top: { + 'chain: { + let Ok(_) = e.ok(1).as_ref() else { break 'chain }; + // The "then" branch: + e.mark(2); + break 'top; + } + // The "else" branch: + unreachable!() + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_let_else_else() { + let e = Events::new(); + _ = ('top: { + 'chain: { + let Ok(_) = e.err(1).as_ref() else { break 'chain }; + // The "then" branch: + unreachable!(); + #[allow(unreachable_code)] + break 'top; + } + // The "else" branch: + e.mark(2); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_then_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.ok(4).as_ref() { + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + } + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_then_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.ok(2).as_ref() { + e.mark(1); + } + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_else_tailexpr() { + let e = Events::new(); + _ = ({ + match e.err(4).as_ref() { Ok(_) => {} _ => { + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + //[e2021]~| WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + }} + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_else_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.err(1).as_ref() {} else { + e.mark(2); + } + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_if_let_nested_then() { + let e = Events::new(); + _ = { + // The unusual formatting, here and below, is to make the + // comparison with `let` chains more direct. + if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.ok(4).as_ref() { + e.mark(3); + }}}}}}}} + }; + e.assert(9); +} + +#[rustfmt::skip] +fn t_let_else_chained_then() { + let e = Events::new(); + _ = 'top: { + 'chain: { + if e.ok(1).is_ok() {} else { break 'chain }; + let true = e.ok(2).is_ok() else { break 'chain }; + let Ok(_v) = e.ok(9) else { break 'chain }; + let Ok(_) = e.ok(3) else { break 'chain }; + let Ok(_) = e.ok(4).as_ref() else { break 'chain }; + if e.ok(5).is_ok() {} else { break 'chain }; + let Ok(_v) = e.ok(8) else { break 'chain }; + let Ok(_) = e.ok(6).as_ref() else { break 'chain }; + // The "then" branch: + e.mark(7); + break 'top; + } + // The "else" branch: + unreachable!() + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_chains_then() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(8) + && let Ok(_) = e.ok(7).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.ok(6).as_ref() { + e.mark(3); + }; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_chains_then() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(8) + && let Ok(_) = e.ok(7) + && let Ok(_) = e.ok(6).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(4).as_ref() { + e.mark(3); + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_nested_else() { + let e = Events::new(); + _ = if e.err(1).is_ok() {} else { + match e.err(9).is_ok() { true => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + match e.err(8) { Ok(_v) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + match e.err(7) { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + match e.err(6).as_ref() { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if e.err(2).is_ok() {} else { + match e.err(5) { Ok(_v) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + match e.err(4) { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(3); + }}}}}}}}}}}}}}; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_nested_else() { + let e = Events::new(); + _ = if e.err(1).is_ok() {} else { + if let true = e.err(2).is_ok() {} else { + if let Ok(_v) = e.err(3) {} else { + if let Ok(_) = e.err(4) {} else { + if let Ok(_) = e.err(5).as_ref() {} else { + if e.err(6).is_ok() {} else { + if let Ok(_v) = e.err(7) {} else { + if let Ok(_) = e.err(8) {} else { + e.mark(9); + }}}}}}}}; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_nested_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + match e.err(4).as_ref() { Ok(_) => {} _ => { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(3); + }}}}}}}}}; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_nested_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.err(3).as_ref() {} else { + e.mark(4); + }}}}}}}}; + e.assert(9); +} + +#[rustfmt::skip] +fn t_let_else_chained_then_else() { + let e = Events::new(); + _ = 'top: { + 'chain: { + if e.ok(1).is_ok() {} else { break 'chain }; + let true = e.ok(2).is_ok() else { break 'chain }; + let Ok(_v) = e.ok(8) else { break 'chain }; + let Ok(_) = e.ok(3) else { break 'chain }; + let Ok(_) = e.ok(4).as_ref() else { break 'chain }; + if e.ok(5).is_ok() {} else { break 'chain }; + let Ok(_v) = e.ok(7) else { break 'chain }; + let Ok(_) = e.err(6).as_ref() else { break 'chain }; + // The "then" branch: + unreachable!(); + #[allow(unreachable_code)] + break 'top; + } + // The "else" branch: + e.mark(9); + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_chains_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.ok(8) + && let Ok(_) = e.ok(7).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(3) + && let Ok(_) = e.err(6) {} else { + e.mark(5); + }; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_chains_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(8).is_ok() + && let Ok(_v) = e.ok(7) + && let Ok(_) = e.ok(6) + && let Ok(_) = e.ok(5).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.err(3) {} else { + e.mark(9); + }; + e.assert(9); +} + +fn main() { + t_bindings(); + t_tuples(); + t_arrays(); + t_fncalls(); + t_tailexpr_bindings(); + t_tailexpr_tuples(); + t_if_let_then(); + t_if_let_else(); + t_match_then(); + t_match_else(); + t_let_else_then(); + t_let_else_else(); + t_if_let_then_tailexpr(); + t_if_let_else_tailexpr(); + t_if_let_nested_then(); + t_let_else_chained_then(); + t_if_let_chains_then(); + t_if_let_nested_else(); + t_if_let_nested_then_else(); + t_let_else_chained_then_else(); + t_if_let_chains_then_else(); +} + +// # Test scaffolding + +use core::cell::RefCell; +use std::collections::HashSet; + +/// A buffer to track the order of events. +/// +/// First, numbered events are logged into this buffer. +/// +/// Then, `assert` is called to verify that the correct number of +/// events were logged, and that they were logged in the expected +/// order. +struct Events(RefCell<Option<Vec<u64>>>); + +impl Events { + const fn new() -> Self { + Self(RefCell::new(Some(Vec::new()))) + } + #[track_caller] + fn assert(&self, max: u64) { + let buf = &self.0; + let v1 = buf.borrow().as_ref().unwrap().clone(); + let mut v2 = buf.borrow().as_ref().unwrap().clone(); + *buf.borrow_mut() = None; + v2.sort(); + let uniq_len = v2.iter().collect::<HashSet<_>>().len(); + // Check that the sequence is sorted. + assert_eq!(v1, v2); + // Check that there are no duplicates. + assert_eq!(v2.len(), uniq_len); + // Check that the length is the expected one. + assert_eq!(max, uniq_len as u64); + // Check that the last marker is the expected one. + assert_eq!(v2.last().unwrap(), &max); + } + /// Return an `Ok` value that logs its drop. + fn ok(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> { + Ok(LogDrop(self, m)) + } + /// Return an `Err` value that logs its drop. + fn err(&self, m: u64) -> Result<LogDrop, LogDrop> { + Err(LogDrop(self, m)) + } + /// Log an event. + fn mark(&self, m: u64) { + self.0.borrow_mut().as_mut().unwrap().push(m); + } +} + +impl Drop for Events { + fn drop(&mut self) { + if self.0.borrow().is_some() { + panic!("failed to call `Events::assert()`"); + } + } +} + +/// A type that logs its drop events. +struct LogDrop<'b>(&'b Events, u64); + +impl<'b> Drop for LogDrop<'b> { + fn drop(&mut self) { + self.0.mark(self.1); + } +} diff --git a/tests/ui/drop/drop-order-comparisons.e2021.stderr b/tests/ui/drop/drop-order-comparisons.e2021.stderr new file mode 100644 index 00000000000..158d18f6882 --- /dev/null +++ b/tests/ui/drop/drop-order-comparisons.e2021.stderr @@ -0,0 +1,477 @@ +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:76:9 + | +LL | _ = ({ + | _________- +LL | | let _v = e.ok(2); + | | -- + | | | + | | `_v` calls a custom destructor + | | `_v` will be dropped later as of Edition 2024 +LL | | let _v = e.ok(1); + | | -- + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | `#2` will be dropped later as of Edition 2024 +LL | | e.ok(5).is_ok() + | | ^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#3` + | | up until Edition 2021 `#3` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(3), e.ok(4)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> +note: `#3` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `_v` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages +note: the lint level is defined here + --> $DIR/drop-order-comparisons.rs:28:25 + | +LL | #![cfg_attr(e2021, warn(rust_2024_compatibility))] + | ^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(tail_expr_drop_order)]` implied by `#[warn(rust_2024_compatibility)]` + +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:100:45 + | +LL | _ = ({ + | _________- +LL | | (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok()) + | | ^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(1), e.ok(4)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:100:19 + | +LL | _ = ({ + | _________- +LL | | (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok()) + | | ^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(1), e.ok(4)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:221:24 + | +LL | _ = ({ + | _________- +LL | | if let Ok(_) = e.ok(4).as_ref() { + | | ^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(2), e.ok(3)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +warning: relative drop order changing in Rust 2024 + --> $DIR/drop-order-comparisons.rs:247:24 + | +LL | _ = ({ + | _________- +LL | | if let Ok(_) = e.err(4).as_ref() {} else { + | | ^^^^^^^^ + | | | + | | this value will be stored in a temporary; let us call it `#2` + | | up until Edition 2021 `#2` is dropped last but will be dropped earlier in Edition 2024 +... | +LL | | }, e.mark(2), e.ok(3)); + | | - + | | | + | | now the temporary value is dropped here, before the local variables in the block or statement + | |__________________________this value will be stored in a temporary; let us call it `#1` + | `#1` will be dropped later as of Edition 2024 + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-tail-expr-scope.html> +note: `#2` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ +note: `#1` invokes this custom destructor + --> $DIR/drop-order-comparisons.rs:571:1 + | +LL | / impl<'b> Drop for LogDrop<'b> { +LL | | fn drop(&mut self) { +LL | | self.0.mark(self.1); +LL | | } +LL | | } + | |_^ + = note: most of the time, changing drop order is harmless; inspect the `impl Drop`s for side effects like releasing locks or sending messages + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:123:13 + | +LL | _ = (if let Ok(_) = e.ok(4).as_ref() { + | ^^^^^^^^^^^^-------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:127:5 + | +LL | }, e.mark(2), e.ok(3)); + | ^ + = note: `#[warn(if_let_rescope)]` implied by `#[warn(rust_2024_compatibility)]` +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ _ = (match e.ok(4).as_ref() { Ok(_) => { +LL | +LL | +LL | e.mark(1); +LL ~ } _ => {}}, e.mark(2), e.ok(3)); + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:145:13 + | +LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { + | ^^^^^^^^^^^^--------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:145:44 + | +LL | _ = (if let Ok(_) = e.err(4).as_ref() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ _ = (match e.err(4).as_ref() { Ok(_) => {} _ => { +LL | +LL | +LL | e.mark(1); +LL ~ }}, e.mark(2), e.ok(3)); + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:247:12 + | +LL | if let Ok(_) = e.err(4).as_ref() {} else { + | ^^^^^^^^^^^^--------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:247:43 + | +LL | if let Ok(_) = e.err(4).as_ref() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(4).as_ref() { Ok(_) => {} _ => { +LL | +... +LL | e.mark(1); +LL ~ }} + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:352:12 + | +LL | if let true = e.err(9).is_ok() {} else { + | ^^^^^^^^^^^--------^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:352:41 + | +LL | if let true = e.err(9).is_ok() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(9).is_ok() { true => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:355:12 + | +LL | if let Ok(_v) = e.err(8) {} else { + | ^^^^^^^^^^^^^-------- + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:355:35 + | +LL | if let Ok(_v) = e.err(8) {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(8) { Ok(_v) => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:358:12 + | +LL | if let Ok(_) = e.err(7) {} else { + | ^^^^^^^^^^^^-------- + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:358:34 + | +LL | if let Ok(_) = e.err(7) {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(7) { Ok(_) => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:361:12 + | +LL | if let Ok(_) = e.err(6).as_ref() {} else { + | ^^^^^^^^^^^^--------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:361:43 + | +LL | if let Ok(_) = e.err(6).as_ref() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(6).as_ref() { Ok(_) => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:365:12 + | +LL | if let Ok(_v) = e.err(5) {} else { + | ^^^^^^^^^^^^^-------- + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:365:35 + | +LL | if let Ok(_v) = e.err(5) {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(5) { Ok(_v) => {} _ => { +LL | +... +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:368:12 + | +LL | if let Ok(_) = e.err(4) {} else { + | ^^^^^^^^^^^^-------- + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:368:34 + | +LL | if let Ok(_) = e.err(4) {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(4) { Ok(_) => {} _ => { +LL | +LL | +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: `if let` assigns a shorter lifetime since Edition 2024 + --> $DIR/drop-order-comparisons.rs:404:12 + | +LL | if let Ok(_) = e.err(4).as_ref() {} else { + | ^^^^^^^^^^^^--------^^^^^^^^^ + | | + | this value has a significant drop implementation which may observe a major change in drop order and requires your discretion + | + = warning: this changes meaning in Rust 2024 + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/temporary-if-let-scope.html> +help: the value is now dropped here in Edition 2024 + --> $DIR/drop-order-comparisons.rs:404:43 + | +LL | if let Ok(_) = e.err(4).as_ref() {} else { + | ^ +help: a `match` with a single arm can preserve the drop order up to Edition 2021 + | +LL ~ match e.err(4).as_ref() { Ok(_) => {} _ => { +LL | +LL | +LL | e.mark(3); +LL ~ }}}}}}}}}; + | + +warning: 15 warnings emitted + diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs new file mode 100644 index 00000000000..78c75a9449f --- /dev/null +++ b/tests/ui/drop/drop-order-comparisons.rs @@ -0,0 +1,575 @@ +// This tests various aspects of the drop order with a focus on: +// +// - The lifetime of temporaries with the `if let` construct (and with +// various similar constructs) and how these lifetimes were shortened +// for `if let` in Rust 2024. +// +// - The shortening of the lifetimes of temporaries in tail +// expressions in Rust 2024. +// +// - The behavior of `let` chains and how this behavior compares to +// nested `if let` expressions and chained `let .. else` statements. +// +// In the tests below, `Events` tracks a sequence of numbered events. +// Calling `e.mark(..)` logs a numbered event immediately. Calling +// `e.ok(..)` or `e.err(..)` returns an `Ok(_)` or `Err(_)` value, +// respectively, and logs the numbered event when that value is +// dropped. Calling `e.assert()` verifies that the correct number of +// events were logged and that they were logged in the correct order. + +//@ revisions: e2021 e2024 +//@ [e2021] edition: 2021 +//@ [e2021] run-rustfix +//@ [e2021] rustfix-only-machine-applicable +//@ [e2024] edition: 2024 +//@ run-pass + +#![feature(let_chains)] +#![cfg_attr(e2021, warn(rust_2024_compatibility))] + +fn t_bindings() { + let e = Events::new(); + _ = { + e.mark(1); + let _v = e.ok(8); + let _v = e.ok(2).is_ok(); + let _ = e.ok(3); + let Ok(_) = e.ok(4) else { unreachable!() }; + let Ok(_) = e.ok(5).as_ref() else { unreachable!() }; + let _v = e.ok(7); + e.mark(6); + }; + e.assert(8); +} + +fn t_tuples() { + let e = Events::new(); + _ = (e.ok(1), e.ok(4).is_ok(), e.ok(2), e.ok(3).is_ok()); + e.assert(4); +} + +fn t_arrays() { + let e = Events::new(); + trait Tr {} + impl<T> Tr for T {} + fn b<'a, T: 'a>(x: T) -> Box<dyn Tr + 'a> { + Box::new(x) + } + _ = [b(e.ok(1)), b(e.ok(4).is_ok()), b(e.ok(2)), b(e.ok(3).is_ok())]; + e.assert(4); +} + +fn t_fncalls() { + let e = Events::new(); + let f = |_, _, _, _| {}; + _ = f(e.ok(2), e.ok(4).is_ok(), e.ok(1), e.ok(3).is_ok()); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_tailexpr_bindings() { + let e = Events::new(); + _ = ({ + let _v = e.ok(2); + let _v = e.ok(1); + e.ok(5).is_ok() + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + }, e.mark(3), e.ok(4)); + e.assert(5); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_tailexpr_bindings() { + let e = Events::new(); + _ = ({ + let _v = e.ok(3); + let _v = e.ok(2); + e.ok(1).is_ok() + }, e.mark(4), e.ok(5)); + e.assert(5); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_tailexpr_tuples() { + let e = Events::new(); + _ = ({ + (e.ok(2), e.ok(6).is_ok(), e.ok(3), e.ok(5).is_ok()) + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + //[e2021]~| WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + }, e.mark(1), e.ok(4)); + e.assert(6); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_tailexpr_tuples() { + let e = Events::new(); + _ = ({ + (e.ok(4), e.ok(2).is_ok(), e.ok(5), e.ok(1).is_ok()) + }, e.mark(3), e.ok(6)); + e.assert(6); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_then() { + let e = Events::new(); + _ = (if let Ok(_) = e.ok(4).as_ref() { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_then() { + let e = Events::new(); + _ = (if let Ok(_) = e.ok(2).as_ref() { + e.mark(1); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_else() { + let e = Events::new(); + _ = (if let Ok(_) = e.err(4).as_ref() {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_else() { + let e = Events::new(); + _ = (if let Ok(_) = e.err(1).as_ref() {} else { + e.mark(2); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_match_then() { + let e = Events::new(); + _ = (match e.ok(4).as_ref() { + Ok(_) => e.mark(1), + _ => unreachable!(), + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_match_else() { + let e = Events::new(); + _ = (match e.err(4).as_ref() { + Ok(_) => unreachable!(), + _ => e.mark(1), + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_let_else_then() { + let e = Events::new(); + _ = ('top: { + 'chain: { + let Ok(_) = e.ok(1).as_ref() else { break 'chain }; + // The "then" branch: + e.mark(2); + break 'top; + } + // The "else" branch: + unreachable!() + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_let_else_else() { + let e = Events::new(); + _ = ('top: { + 'chain: { + let Ok(_) = e.err(1).as_ref() else { break 'chain }; + // The "then" branch: + unreachable!(); + #[allow(unreachable_code)] + break 'top; + } + // The "else" branch: + e.mark(2); + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_then_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.ok(4).as_ref() { + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + } + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_then_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.ok(2).as_ref() { + e.mark(1); + } + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_else_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.err(4).as_ref() {} else { + //[e2021]~^ WARN relative drop order changing in Rust 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + //[e2021]~| WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(1); + } + }, e.mark(2), e.ok(3)); + e.assert(4); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_else_tailexpr() { + let e = Events::new(); + _ = ({ + if let Ok(_) = e.err(1).as_ref() {} else { + e.mark(2); + } + }, e.mark(3), e.ok(4)); + e.assert(4); +} + +#[rustfmt::skip] +fn t_if_let_nested_then() { + let e = Events::new(); + _ = { + // The unusual formatting, here and below, is to make the + // comparison with `let` chains more direct. + if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.ok(4).as_ref() { + e.mark(3); + }}}}}}}} + }; + e.assert(9); +} + +#[rustfmt::skip] +fn t_let_else_chained_then() { + let e = Events::new(); + _ = 'top: { + 'chain: { + if e.ok(1).is_ok() {} else { break 'chain }; + let true = e.ok(2).is_ok() else { break 'chain }; + let Ok(_v) = e.ok(9) else { break 'chain }; + let Ok(_) = e.ok(3) else { break 'chain }; + let Ok(_) = e.ok(4).as_ref() else { break 'chain }; + if e.ok(5).is_ok() {} else { break 'chain }; + let Ok(_v) = e.ok(8) else { break 'chain }; + let Ok(_) = e.ok(6).as_ref() else { break 'chain }; + // The "then" branch: + e.mark(7); + break 'top; + } + // The "else" branch: + unreachable!() + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_chains_then() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(8) + && let Ok(_) = e.ok(7).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.ok(6).as_ref() { + e.mark(3); + }; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_chains_then() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(8) + && let Ok(_) = e.ok(7) + && let Ok(_) = e.ok(6).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(5) + && let Ok(_) = e.ok(4).as_ref() { + e.mark(3); + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_nested_else() { + let e = Events::new(); + _ = if e.err(1).is_ok() {} else { + if let true = e.err(9).is_ok() {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if let Ok(_v) = e.err(8) {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if let Ok(_) = e.err(7) {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if let Ok(_) = e.err(6).as_ref() {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if e.err(2).is_ok() {} else { + if let Ok(_v) = e.err(5) {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + if let Ok(_) = e.err(4) {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(3); + }}}}}}}}; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_nested_else() { + let e = Events::new(); + _ = if e.err(1).is_ok() {} else { + if let true = e.err(2).is_ok() {} else { + if let Ok(_v) = e.err(3) {} else { + if let Ok(_) = e.err(4) {} else { + if let Ok(_) = e.err(5).as_ref() {} else { + if e.err(6).is_ok() {} else { + if let Ok(_v) = e.err(7) {} else { + if let Ok(_) = e.err(8) {} else { + e.mark(9); + }}}}}}}}; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_nested_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.err(4).as_ref() {} else { + //[e2021]~^ WARN if let` assigns a shorter lifetime since Edition 2024 + //[e2021]~| WARN this changes meaning in Rust 2024 + e.mark(3); + }}}}}}}}; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_nested_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() { + if let true = e.ok(9).is_ok() { + if let Ok(_v) = e.ok(8) { + if let Ok(_) = e.ok(7) { + if let Ok(_) = e.ok(6).as_ref() { + if e.ok(2).is_ok() { + if let Ok(_v) = e.ok(5) { + if let Ok(_) = e.err(3).as_ref() {} else { + e.mark(4); + }}}}}}}}; + e.assert(9); +} + +#[rustfmt::skip] +fn t_let_else_chained_then_else() { + let e = Events::new(); + _ = 'top: { + 'chain: { + if e.ok(1).is_ok() {} else { break 'chain }; + let true = e.ok(2).is_ok() else { break 'chain }; + let Ok(_v) = e.ok(8) else { break 'chain }; + let Ok(_) = e.ok(3) else { break 'chain }; + let Ok(_) = e.ok(4).as_ref() else { break 'chain }; + if e.ok(5).is_ok() {} else { break 'chain }; + let Ok(_v) = e.ok(7) else { break 'chain }; + let Ok(_) = e.err(6).as_ref() else { break 'chain }; + // The "then" branch: + unreachable!(); + #[allow(unreachable_code)] + break 'top; + } + // The "else" branch: + e.mark(9); + }; + e.assert(9); +} + +#[cfg(e2021)] +#[rustfmt::skip] +fn t_if_let_chains_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(9).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.ok(8) + && let Ok(_) = e.ok(7).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(3) + && let Ok(_) = e.err(6) {} else { + e.mark(5); + }; + e.assert(9); +} + +#[cfg(e2024)] +#[rustfmt::skip] +fn t_if_let_chains_then_else() { + let e = Events::new(); + _ = if e.ok(1).is_ok() + && let true = e.ok(8).is_ok() + && let Ok(_v) = e.ok(7) + && let Ok(_) = e.ok(6) + && let Ok(_) = e.ok(5).as_ref() + && e.ok(2).is_ok() + && let Ok(_v) = e.ok(4) + && let Ok(_) = e.err(3) {} else { + e.mark(9); + }; + e.assert(9); +} + +fn main() { + t_bindings(); + t_tuples(); + t_arrays(); + t_fncalls(); + t_tailexpr_bindings(); + t_tailexpr_tuples(); + t_if_let_then(); + t_if_let_else(); + t_match_then(); + t_match_else(); + t_let_else_then(); + t_let_else_else(); + t_if_let_then_tailexpr(); + t_if_let_else_tailexpr(); + t_if_let_nested_then(); + t_let_else_chained_then(); + t_if_let_chains_then(); + t_if_let_nested_else(); + t_if_let_nested_then_else(); + t_let_else_chained_then_else(); + t_if_let_chains_then_else(); +} + +// # Test scaffolding + +use core::cell::RefCell; +use std::collections::HashSet; + +/// A buffer to track the order of events. +/// +/// First, numbered events are logged into this buffer. +/// +/// Then, `assert` is called to verify that the correct number of +/// events were logged, and that they were logged in the expected +/// order. +struct Events(RefCell<Option<Vec<u64>>>); + +impl Events { + const fn new() -> Self { + Self(RefCell::new(Some(Vec::new()))) + } + #[track_caller] + fn assert(&self, max: u64) { + let buf = &self.0; + let v1 = buf.borrow().as_ref().unwrap().clone(); + let mut v2 = buf.borrow().as_ref().unwrap().clone(); + *buf.borrow_mut() = None; + v2.sort(); + let uniq_len = v2.iter().collect::<HashSet<_>>().len(); + // Check that the sequence is sorted. + assert_eq!(v1, v2); + // Check that there are no duplicates. + assert_eq!(v2.len(), uniq_len); + // Check that the length is the expected one. + assert_eq!(max, uniq_len as u64); + // Check that the last marker is the expected one. + assert_eq!(v2.last().unwrap(), &max); + } + /// Return an `Ok` value that logs its drop. + fn ok(&self, m: u64) -> Result<LogDrop<'_>, LogDrop<'_>> { + Ok(LogDrop(self, m)) + } + /// Return an `Err` value that logs its drop. + fn err(&self, m: u64) -> Result<LogDrop, LogDrop> { + Err(LogDrop(self, m)) + } + /// Log an event. + fn mark(&self, m: u64) { + self.0.borrow_mut().as_mut().unwrap().push(m); + } +} + +impl Drop for Events { + fn drop(&mut self) { + if self.0.borrow().is_some() { + panic!("failed to call `Events::assert()`"); + } + } +} + +/// A type that logs its drop events. +struct LogDrop<'b>(&'b Events, u64); + +impl<'b> Drop for LogDrop<'b> { + fn drop(&mut self) { + self.0.mark(self.1); + } +} diff --git a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr index d73a878c74f..029d5c74929 100644 --- a/tests/ui/drop/lint-if-let-rescope-with-macro.stderr +++ b/tests/ui/drop/lint-if-let-rescope-with-macro.stderr @@ -2,7 +2,7 @@ error: `if let` assigns a shorter lifetime since Edition 2024 --> $DIR/lint-if-let-rescope-with-macro.rs:12:12 | LL | if let $p = $e { $($conseq)* } else { $($alt)* } - | ^^^ + | ^^^^^^^^^^^ ... LL | / edition_2021_if_let! { LL | | Some(_value), diff --git a/tests/ui/duplicate/dupe-symbols-7.stderr b/tests/ui/duplicate/dupe-symbols-7.stderr index ab9167e005a..aa6213af2e4 100644 --- a/tests/ui/duplicate/dupe-symbols-7.stderr +++ b/tests/ui/duplicate/dupe-symbols-7.stderr @@ -4,7 +4,7 @@ error: entry symbol `main` declared multiple times LL | fn main(){} | ^^^^^^^^^ | - = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead + = help: did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point error: aborting due to 1 previous error diff --git a/tests/ui/duplicate/dupe-symbols-8.stderr b/tests/ui/duplicate/dupe-symbols-8.stderr index d7d419c9aa4..0f47d3683b5 100644 --- a/tests/ui/duplicate/dupe-symbols-8.stderr +++ b/tests/ui/duplicate/dupe-symbols-8.stderr @@ -4,7 +4,7 @@ error: entry symbol `main` declared multiple times LL | fn main() { | ^^^^^^^^^ | - = help: did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead + = help: did you use `#[no_mangle]` on `fn main`? Use `#![no_main]` to suppress the usual Rust-generated entry point error: aborting due to 1 previous error diff --git a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs index 83076f7d5fc..1b1b8bcf03d 100644 --- a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs +++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.rs @@ -5,8 +5,8 @@ use std::marker::PhantomData; fn transmute<T, U>(t: T) -> U { (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t) - //~^ ERROR the trait `Foo` cannot be made into an object - //~| ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible + //~| ERROR the trait `Foo` is not dyn compatible } struct ActuallySuper; @@ -19,7 +19,7 @@ trait Dyn { type Out; } impl<T, U> Dyn for dyn Foo<T, U> + '_ { -//~^ ERROR the trait `Foo` cannot be made into an object +//~^ ERROR the trait `Foo` is not dyn compatible type Out = U; } impl<S: Dyn<Out = U> + ?Sized, U> Super<NotActuallySuper> for S { diff --git a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr index 99bcccc20c0..f241333f2a7 100644 --- a/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr +++ b/tests/ui/dyn-compatibility/almost-supertrait-associated-type.stderr @@ -1,53 +1,53 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/almost-supertrait-associated-type.rs:21:20 | LL | impl<T, U> Dyn for dyn Foo<T, U> + '_ { - | ^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/almost-supertrait-associated-type.rs:33:34 | LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T> - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... ... LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type = help: consider moving `transmute` to another trait - = help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/almost-supertrait-associated-type.rs:7:27 | LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t) - | ^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/almost-supertrait-associated-type.rs:33:34 | LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T> - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... ... LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type = help: consider moving `transmute` to another trait - = help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/almost-supertrait-associated-type.rs:7:6 | LL | (&PhantomData::<T> as &dyn Foo<T, U>).transmute(t) - | ^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/almost-supertrait-associated-type.rs:33:34 | LL | trait Foo<T, U>: Super<ActuallySuper, Assoc = T> - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... ... LL | fn transmute(&self, t: T) -> <Self as Super<NotActuallySuper>>::Assoc; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because method `transmute` references the `Self` type in its return type = help: consider moving `transmute` to another trait - = help: only type `std::marker::PhantomData<T>` implements the trait, consider using it directly instead = note: required for the cast from `&PhantomData<T>` to `&dyn Foo<T, U>` error: aborting due to 3 previous errors diff --git a/tests/ui/dyn-compatibility/associated-consts.curr.stderr b/tests/ui/dyn-compatibility/associated-consts.curr.stderr index 17d184942c7..45d4f795542 100644 --- a/tests/ui/dyn-compatibility/associated-consts.curr.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.curr.stderr @@ -1,29 +1,31 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/associated-consts.rs:12:31 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { - | ^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/associated-consts.rs:9:11 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | const X: usize; | ^ ...because it contains this associated `const` = help: consider moving `X` to another trait -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/associated-consts.rs:14:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/associated-consts.rs:9:11 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | const X: usize; | ^ ...because it contains this associated `const` = help: consider moving `X` to another trait diff --git a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr index cc5120232c2..4c8c82196ed 100644 --- a/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/associated-consts.dyn_compatible_for_dispatch.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/associated-consts.rs:14:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/associated-consts.rs:9:11 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | const X: usize; | ^ ...because it contains this associated `const` = help: consider moving `X` to another trait diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr index 54daefea31c..ff5e9fdb6b3 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.old.stderr @@ -26,14 +26,15 @@ help: if this is a dyn-compatible trait, use `dyn` LL | fn id<F>(f: dyn Copy) -> usize { | +++ -error[E0038]: the trait `Copy` cannot be made into an object +error[E0038]: the trait `Copy` is not dyn compatible --> $DIR/avoid-ice-on-warning-2.rs:4:13 | LL | fn id<F>(f: Copy) -> usize { - | ^^^^ `Copy` cannot be made into an object + | ^^^^ `Copy` is not dyn compatible | - = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "dyn-compatible" 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> + = note: the trait is not dyn compatible because it requires `Self: Sized` + = note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> error[E0618]: expected function, found `(dyn Copy + 'static)` --> $DIR/avoid-ice-on-warning-2.rs:12:5 diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs index 3c2da667b39..312e0d666f1 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-2.rs @@ -3,7 +3,7 @@ //@[new] edition:2021 fn id<F>(f: Copy) -> usize { //[new]~^ ERROR expected a type, found a trait -//[old]~^^ ERROR the trait `Copy` cannot be made into an object +//[old]~^^ ERROR the trait `Copy` is not dyn compatible //[old]~| ERROR the size for values of type `(dyn Copy + 'static)` //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr index 6bc2d73a0d0..92a2d340115 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.old.stderr @@ -65,19 +65,20 @@ help: if this is a dyn-compatible trait, use `dyn` LL | trait B { fn f(a: dyn A) -> A; } | +++ -error[E0038]: the trait `A` cannot be made into an object +error[E0038]: the trait `A` is not dyn compatible --> $DIR/avoid-ice-on-warning-3.rs:4:19 | LL | trait B { fn f(a: A) -> A; } - | ^ `A` cannot be made into an object + | ^ `A` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/avoid-ice-on-warning-3.rs:14:14 | LL | trait A { fn g(b: B) -> B; } | - ^ ...because associated function `g` has no `self` parameter | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... help: consider turning `g` into a method by giving it a `&self` argument | LL | trait A { fn g(&self, b: B) -> B; } @@ -101,19 +102,20 @@ help: if this is a dyn-compatible trait, use `dyn` LL | trait A { fn g(b: dyn B) -> B; } | +++ -error[E0038]: the trait `B` cannot be made into an object +error[E0038]: the trait `B` is not dyn compatible --> $DIR/avoid-ice-on-warning-3.rs:14:19 | LL | trait A { fn g(b: B) -> B; } - | ^ `B` cannot be made into an object + | ^ `B` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/avoid-ice-on-warning-3.rs:4:14 | LL | trait B { fn f(a: A) -> A; } | - ^ ...because associated function `f` has no `self` parameter | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... help: consider turning `f` into a method by giving it a `&self` argument | LL | trait B { fn f(&self, a: A) -> A; } diff --git a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs index 00d47225e92..9ccbfc15a0d 100644 --- a/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs +++ b/tests/ui/dyn-compatibility/avoid-ice-on-warning-3.rs @@ -4,7 +4,7 @@ trait B { fn f(a: A) -> A; } //[new]~^ ERROR expected a type, found a trait //[new]~| ERROR expected a type, found a trait -//[old]~^^^ ERROR the trait `A` cannot be made into an object +//[old]~^^^ ERROR the trait `A` is not dyn compatible //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN trait objects without an explicit `dyn` are deprecated @@ -14,7 +14,7 @@ trait B { fn f(a: A) -> A; } trait A { fn g(b: B) -> B; } //[new]~^ ERROR expected a type, found a trait //[new]~| ERROR expected a type, found a trait -//[old]~^^^ ERROR the trait `B` cannot be made into an object +//[old]~^^^ ERROR the trait `B` is not dyn compatible //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN trait objects without an explicit `dyn` are deprecated //[old]~| WARN trait objects without an explicit `dyn` are deprecated diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed index a54892afd3e..b5200e9fff5 100644 --- a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed +++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.new.fixed @@ -5,7 +5,7 @@ #![deny(bare_trait_objects)] fn ord_prefer_dot(s: String) -> impl Ord { //[new]~^ ERROR expected a type, found a trait - //[old]~^^ ERROR the trait `Ord` cannot be made into an object + //[old]~^^ ERROR the trait `Ord` is not dyn compatible //[old]~| ERROR trait objects without an explicit `dyn` are deprecated //[old]~| WARNING this is accepted in the current edition (Rust 2015) (s.starts_with("."), s) diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr index 45c9b0ce5d9..e3ec5b9c3c8 100644 --- a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr +++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.old.stderr @@ -16,19 +16,20 @@ help: if this is a dyn-compatible trait, use `dyn` LL | fn ord_prefer_dot(s: String) -> dyn Ord { | +++ -error[E0038]: the trait `Ord` cannot be made into an object +error[E0038]: the trait `Ord` is not dyn compatible --> $DIR/bare-trait-dont-suggest-dyn.rs:6:33 | LL | fn ord_prefer_dot(s: String) -> Ord { - | ^^^ `Ord` cannot be made into an object + | ^^^ `Ord` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $SRC_DIR/core/src/cmp.rs:LL:COL | - = note: the trait cannot be made into an object because it uses `Self` as a type parameter + = note: the trait is not dyn compatible because it uses `Self` as a type parameter ::: $SRC_DIR/core/src/cmp.rs:LL:COL | - = note: the trait cannot be made into an object because it uses `Self` as a type parameter + = note: the trait is not dyn compatible because it uses `Self` as a type parameter help: consider using an opaque type instead | LL | fn ord_prefer_dot(s: String) -> impl Ord { diff --git a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs index cf9be612d2e..385fd48102c 100644 --- a/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs +++ b/tests/ui/dyn-compatibility/bare-trait-dont-suggest-dyn.rs @@ -5,7 +5,7 @@ #![deny(bare_trait_objects)] fn ord_prefer_dot(s: String) -> Ord { //[new]~^ ERROR expected a type, found a trait - //[old]~^^ ERROR the trait `Ord` cannot be made into an object + //[old]~^^ ERROR the trait `Ord` is not dyn compatible //[old]~| ERROR trait objects without an explicit `dyn` are deprecated //[old]~| WARNING this is accepted in the current edition (Rust 2015) (s.starts_with("."), s) diff --git a/tests/ui/dyn-compatibility/bounds.rs b/tests/ui/dyn-compatibility/bounds.rs index 1e04d11c516..ed4a69129af 100644 --- a/tests/ui/dyn-compatibility/bounds.rs +++ b/tests/ui/dyn-compatibility/bounds.rs @@ -5,7 +5,7 @@ trait X { } fn f() -> Box<dyn X<U = u32>> { - //~^ ERROR the trait `X` cannot be made into an object + //~^ ERROR the trait `X` is not dyn compatible loop {} } diff --git a/tests/ui/dyn-compatibility/bounds.stderr b/tests/ui/dyn-compatibility/bounds.stderr index 9231d524fd1..d45e66b1d5e 100644 --- a/tests/ui/dyn-compatibility/bounds.stderr +++ b/tests/ui/dyn-compatibility/bounds.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/bounds.rs:7:15 | LL | fn f() -> Box<dyn X<U = u32>> { - | ^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/bounds.rs:4:13 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type U: PartialEq<Self>; | ^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter diff --git a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.rs b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.rs new file mode 100644 index 00000000000..fff29ac2b51 --- /dev/null +++ b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.rs @@ -0,0 +1,18 @@ +// Test that the dyn-compatibility diagnostics for GATs refer first to the +// user-named trait, not the GAT-containing supertrait. +// +// NOTE: this test is currently broken, and first reports: +// "the trait `Super` is not dyn compatible" +// +//@ edition:2018 + +trait Super { + type Assoc<'a>; +} + +trait Child: Super {} + +fn take_dyn(_: &dyn Child) {} +//~^ ERROR the trait `Super` is not dyn compatible + +fn main() {} diff --git a/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr new file mode 100644 index 00000000000..04dc0b1d6f4 --- /dev/null +++ b/tests/ui/dyn-compatibility/gat-incompatible-supertrait.stderr @@ -0,0 +1,19 @@ +error[E0038]: the trait `Super` is not dyn compatible + --> $DIR/gat-incompatible-supertrait.rs:15:21 + | +LL | fn take_dyn(_: &dyn Child) {} + | ^^^^^ `Super` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/gat-incompatible-supertrait.rs:10:10 + | +LL | trait Super { + | ----- this trait is not dyn compatible... +LL | type Assoc<'a>; + | ^^^^^ ...because it contains the generic associated type `Assoc` + = help: consider moving `Assoc` to another trait + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/dyn-compatibility/generics.curr.stderr b/tests/ui/dyn-compatibility/generics.curr.stderr index c63db38a080..1607954ab70 100644 --- a/tests/ui/dyn-compatibility/generics.curr.stderr +++ b/tests/ui/dyn-compatibility/generics.curr.stderr @@ -1,75 +1,80 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/generics.rs:18:31 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { - | ^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/generics.rs:10:8 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar<T>(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/generics.rs:25:40 | LL | fn make_bar_explicit<T:Bar>(t: &T) -> &dyn Bar { - | ^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/generics.rs:10:8 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar<T>(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/generics.rs:20:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/generics.rs:10:8 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar<T>(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait = note: required for the cast from `&T` to `&dyn Bar` -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/generics.rs:27:10 | LL | t as &dyn Bar - | ^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/generics.rs:10:8 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar<T>(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/generics.rs:27:5 | LL | t as &dyn Bar - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/generics.rs:10:8 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar<T>(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait diff --git a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr index ba2546ef2dc..7f31b29b39c 100644 --- a/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/generics.dyn_compatible_for_dispatch.stderr @@ -1,30 +1,32 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/generics.rs:20:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/generics.rs:10:8 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar<T>(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait = note: required for the cast from `&T` to `&dyn Bar` -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/generics.rs:27:5 | LL | t as &dyn Bar - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/generics.rs:10:8 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar<T>(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait diff --git a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr index 7378ec023c9..1ed78e1e659 100644 --- a/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr +++ b/tests/ui/dyn-compatibility/mention-correct-dyn-incompatible-trait.stderr @@ -1,36 +1,38 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:15 | LL | let test: &mut dyn Bar = &mut thing; - | ^^^^^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 | LL | fn foo<T>(&self, val: T); | ^^^ ...because method `foo` has generic type parameters ... LL | trait Bar: Foo { } - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait - = help: only type `Thing` implements the trait, consider using it directly instead + = help: only type `Thing` implements `Bar`; consider using it directly instead. -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/mention-correct-dyn-incompatible-trait.rs:19:30 | LL | let test: &mut dyn Bar = &mut thing; - | ^^^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mention-correct-dyn-incompatible-trait.rs:4:8 | LL | fn foo<T>(&self, val: T); | ^^^ ...because method `foo` has generic type parameters ... LL | trait Bar: Foo { } - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait - = help: only type `Thing` implements the trait, consider using it directly instead + = help: only type `Thing` implements `Bar`; consider using it directly instead. = note: required for the cast from `&mut Thing` to `&mut dyn Bar` error: aborting due to 2 previous errors diff --git a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs index c9ec44cc0b8..2ab0c6c8f5d 100644 --- a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs +++ b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.rs @@ -36,9 +36,9 @@ impl <'x> Expr for SExpr<'x> { fn main() { let a: Box<dyn Expr> = Box::new(SExpr::new()); - //~^ ERROR: `Expr` cannot be made into an object + //~^ ERROR: `Expr` is not dyn compatible let b: Box<dyn Expr> = Box::new(SExpr::new()); - //~^ ERROR: `Expr` cannot be made into an object + //~^ ERROR: `Expr` is not dyn compatible // assert_eq!(a , b); } diff --git a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr index 7578edce7d1..eba2c15dd74 100644 --- a/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self-in-super-predicates.stderr @@ -1,47 +1,47 @@ -error[E0038]: the trait `Expr` cannot be made into an object - --> $DIR/mentions-Self-in-super-predicates.rs:12:23 +error[E0038]: the trait `Expr` is not dyn compatible + --> $DIR/mentions-Self-in-super-predicates.rs:12:27 | LL | elements: Vec<Box<dyn Expr + 'x>>, - | ^^^^^^^^^^^^^ `Expr` cannot be made into an object + | ^^^^ `Expr` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mentions-Self-in-super-predicates.rs:5:21 | LL | trait Expr: Debug + PartialEq { | ---- ^^^^^^^^^ ...because it uses `Self` as a type parameter | | - | this trait cannot be made into an object... - = help: only type `SExpr<'x>` implements the trait, consider using it directly instead + | this trait is not dyn compatible... -error[E0038]: the trait `Expr` cannot be made into an object - --> $DIR/mentions-Self-in-super-predicates.rs:38:16 +error[E0038]: the trait `Expr` is not dyn compatible + --> $DIR/mentions-Self-in-super-predicates.rs:38:20 | LL | let a: Box<dyn Expr> = Box::new(SExpr::new()); - | ^^^^^^^^ `Expr` cannot be made into an object + | ^^^^ `Expr` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mentions-Self-in-super-predicates.rs:5:21 | LL | trait Expr: Debug + PartialEq { | ---- ^^^^^^^^^ ...because it uses `Self` as a type parameter | | - | this trait cannot be made into an object... - = help: only type `SExpr<'x>` implements the trait, consider using it directly instead + | this trait is not dyn compatible... -error[E0038]: the trait `Expr` cannot be made into an object - --> $DIR/mentions-Self-in-super-predicates.rs:40:16 +error[E0038]: the trait `Expr` is not dyn compatible + --> $DIR/mentions-Self-in-super-predicates.rs:40:20 | LL | let b: Box<dyn Expr> = Box::new(SExpr::new()); - | ^^^^^^^^ `Expr` cannot be made into an object + | ^^^^ `Expr` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mentions-Self-in-super-predicates.rs:5:21 | LL | trait Expr: Debug + PartialEq { | ---- ^^^^^^^^^ ...because it uses `Self` as a type parameter | | - | this trait cannot be made into an object... - = help: only type `SExpr<'x>` implements the trait, consider using it directly instead + | this trait is not dyn compatible... error: aborting due to 3 previous errors diff --git a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr index 434e41cf218..90db86ffef9 100644 --- a/tests/ui/dyn-compatibility/mentions-Self.curr.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self.curr.stderr @@ -1,60 +1,64 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/mentions-Self.rs:22:31 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { - | ^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mentions-Self.rs:11:22 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar(&self, x: &Self); | ^^^^^ ...because method `bar` references the `Self` type in this parameter = help: consider moving `bar` to another trait -error[E0038]: the trait `Baz` cannot be made into an object +error[E0038]: the trait `Baz` is not dyn compatible --> $DIR/mentions-Self.rs:28:31 | LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz { - | ^^^^^^^ `Baz` cannot be made into an object + | ^^^^^^^ `Baz` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mentions-Self.rs:15:22 | LL | trait Baz { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn baz(&self) -> Self; | ^^^^ ...because method `baz` references the `Self` type in its return type = help: consider moving `baz` to another trait -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/mentions-Self.rs:24:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mentions-Self.rs:11:22 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar(&self, x: &Self); | ^^^^^ ...because method `bar` references the `Self` type in this parameter = help: consider moving `bar` to another trait = note: required for the cast from `&T` to `&dyn Bar` -error[E0038]: the trait `Baz` cannot be made into an object +error[E0038]: the trait `Baz` is not dyn compatible --> $DIR/mentions-Self.rs:30:5 | LL | t - | ^ `Baz` cannot be made into an object + | ^ `Baz` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mentions-Self.rs:15:22 | LL | trait Baz { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn baz(&self) -> Self; | ^^^^ ...because method `baz` references the `Self` type in its return type = help: consider moving `baz` to another trait diff --git a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr index dc2d1f87eb7..4a50d3f07e4 100644 --- a/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/mentions-Self.dyn_compatible_for_dispatch.stderr @@ -1,30 +1,32 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/mentions-Self.rs:24:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mentions-Self.rs:11:22 | LL | trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar(&self, x: &Self); | ^^^^^ ...because method `bar` references the `Self` type in this parameter = help: consider moving `bar` to another trait = note: required for the cast from `&T` to `&dyn Bar` -error[E0038]: the trait `Baz` cannot be made into an object +error[E0038]: the trait `Baz` is not dyn compatible --> $DIR/mentions-Self.rs:30:5 | LL | t - | ^ `Baz` cannot be made into an object + | ^ `Baz` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/mentions-Self.rs:15:22 | LL | trait Baz { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn baz(&self) -> Self; | ^^^^ ...because method `baz` references the `Self` type in its return type = help: consider moving `baz` to another trait diff --git a/tests/ui/dyn-compatibility/missing-assoc-type.rs b/tests/ui/dyn-compatibility/missing-assoc-type.rs index 21f7fd92e80..135761dd036 100644 --- a/tests/ui/dyn-compatibility/missing-assoc-type.rs +++ b/tests/ui/dyn-compatibility/missing-assoc-type.rs @@ -2,6 +2,6 @@ trait Foo { type Bar<T>; } -fn bar(x: &dyn Foo) {} //~ ERROR the trait `Foo` cannot be made into an object +fn bar(x: &dyn Foo) {} //~ ERROR the trait `Foo` is not dyn compatible fn main() {} diff --git a/tests/ui/dyn-compatibility/missing-assoc-type.stderr b/tests/ui/dyn-compatibility/missing-assoc-type.stderr index 184201dd1ce..3f550494b33 100644 --- a/tests/ui/dyn-compatibility/missing-assoc-type.stderr +++ b/tests/ui/dyn-compatibility/missing-assoc-type.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/missing-assoc-type.rs:5:16 | LL | fn bar(x: &dyn Foo) {} - | ^^^ `Foo` cannot be made into an object + | ^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/missing-assoc-type.rs:2:10 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | type Bar<T>; | ^^^ ...because it contains the generic associated type `Bar` = help: consider moving `Bar` to another trait diff --git a/tests/ui/dyn-compatibility/no-static.curr.stderr b/tests/ui/dyn-compatibility/no-static.curr.stderr index 584db779855..867c485053d 100644 --- a/tests/ui/dyn-compatibility/no-static.curr.stderr +++ b/tests/ui/dyn-compatibility/no-static.curr.stderr @@ -1,17 +1,18 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/no-static.rs:12:22 | LL | fn diverges() -> Box<dyn Foo> { - | ^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/no-static.rs:9:8 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn foo() {} | ^^^ ...because associated function `foo` has no `self` parameter - = help: only type `Bar` implements the trait, consider using it directly instead + = help: only type `Bar` implements `Foo`; consider using it directly instead. help: consider turning `foo` into a method by giving it a `&self` argument | LL | fn foo(&self) {} @@ -21,20 +22,21 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() where Self: Sized {} | +++++++++++++++++ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/no-static.rs:22:12 | LL | let b: Box<dyn Foo> = Box::new(Bar); - | ^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/no-static.rs:9:8 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn foo() {} | ^^^ ...because associated function `foo` has no `self` parameter - = help: only type `Bar` implements the trait, consider using it directly instead + = help: only type `Bar` implements `Foo`; consider using it directly instead. help: consider turning `foo` into a method by giving it a `&self` argument | LL | fn foo(&self) {} @@ -44,20 +46,21 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() where Self: Sized {} | +++++++++++++++++ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/no-static.rs:22:27 | LL | let b: Box<dyn Foo> = Box::new(Bar); - | ^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/no-static.rs:9:8 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn foo() {} | ^^^ ...because associated function `foo` has no `self` parameter - = help: only type `Bar` implements the trait, consider using it directly instead + = help: only type `Bar` implements `Foo`; consider using it directly instead. = note: required for the cast from `Box<Bar>` to `Box<dyn Foo>` help: consider turning `foo` into a method by giving it a `&self` argument | diff --git a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr index f2deb3b8d84..65608a9cca7 100644 --- a/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/no-static.dyn_compatible_for_dispatch.stderr @@ -1,17 +1,18 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/no-static.rs:22:27 | LL | let b: Box<dyn Foo> = Box::new(Bar); - | ^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/no-static.rs:9:8 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn foo() {} | ^^^ ...because associated function `foo` has no `self` parameter - = help: only type `Bar` implements the trait, consider using it directly instead + = help: only type `Bar` implements `Foo`; consider using it directly instead. = note: required for the cast from `Box<Bar>` to `Box<dyn Foo>` help: consider turning `foo` into a method by giving it a `&self` argument | diff --git a/tests/ui/dyn-compatibility/sized-2.curr.stderr b/tests/ui/dyn-compatibility/sized-2.curr.stderr index 1017fde53d3..c8fd1056237 100644 --- a/tests/ui/dyn-compatibility/sized-2.curr.stderr +++ b/tests/ui/dyn-compatibility/sized-2.curr.stderr @@ -1,28 +1,30 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/sized-2.rs:14:31 | LL | fn make_bar<T:Bar>(t: &T) -> &dyn Bar { - | ^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/sized-2.rs:9:18 | LL | trait Bar - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | where Self : Sized | ^^^^^ ...because it requires `Self: Sized` -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/sized-2.rs:16:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/sized-2.rs:9:18 | LL | trait Bar - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | where Self : Sized | ^^^^^ ...because it requires `Self: Sized` = note: required for the cast from `&T` to `&dyn Bar` diff --git a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr index 534cf0f1b03..477dacdf5a1 100644 --- a/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/sized-2.dyn_compatible_for_dispatch.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/sized-2.rs:16:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/sized-2.rs:9:18 | LL | trait Bar - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | where Self : Sized | ^^^^^ ...because it requires `Self: Sized` = note: required for the cast from `&T` to `&dyn Bar` diff --git a/tests/ui/dyn-compatibility/sized.curr.stderr b/tests/ui/dyn-compatibility/sized.curr.stderr index 613833aad12..d86ea9197b9 100644 --- a/tests/ui/dyn-compatibility/sized.curr.stderr +++ b/tests/ui/dyn-compatibility/sized.curr.stderr @@ -1,30 +1,32 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/sized.rs:12:32 | LL | fn make_bar<T: Bar>(t: &T) -> &dyn Bar { - | ^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/sized.rs:8:12 | LL | trait Bar: Sized { | --- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/sized.rs:14:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/sized.rs:8:12 | LL | trait Bar: Sized { | --- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... = note: required for the cast from `&T` to `&dyn Bar` error: aborting due to 2 previous errors diff --git a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr index cf847bc1577..b763173594b 100644 --- a/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/sized.dyn_compatible_for_dispatch.stderr @@ -1,16 +1,17 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/sized.rs:14:5 | LL | t - | ^ `Bar` cannot be made into an object + | ^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/sized.rs:8:12 | LL | trait Bar: Sized { | --- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... = note: required for the cast from `&T` to `&dyn Bar` error: aborting due to 1 previous error diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs index 14e00d2ef32..9e5c1bfe416 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.rs @@ -9,7 +9,7 @@ trait GatTrait { trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> { fn c(&self) -> dyn SuperTrait<T>; //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `SuperTrait` cannot be made into an object + //~| ERROR the trait `SuperTrait` is not dyn compatible } fn main() {} diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr index ac5a5b28d94..f5dea256469 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr +++ b/tests/ui/dyn-compatibility/supertrait-mentions-GAT.stderr @@ -20,20 +20,21 @@ help: you might have meant to use `Self` to refer to the implementing type LL | fn c(&self) -> Self; | ~~~~ -error[E0038]: the trait `SuperTrait` cannot be made into an object +error[E0038]: the trait `SuperTrait` is not dyn compatible --> $DIR/supertrait-mentions-GAT.rs:10:20 | LL | fn c(&self) -> dyn SuperTrait<T>; - | ^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object + | ^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/supertrait-mentions-GAT.rs:4:10 | LL | type Gat<'a> | ^^^ ...because it contains the generic associated type `Gat` ... LL | trait SuperTrait<T>: for<'a> GatTrait<Gat<'a> = T> { - | ---------- this trait cannot be made into an object... + | ---------- this trait is not dyn compatible... = help: consider moving `Gat` to another trait error: aborting due to 3 previous errors diff --git a/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr index 6474b115c46..f9ef0c9b2e0 100644 --- a/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr +++ b/tests/ui/dyn-compatibility/supertrait-mentions-Self.stderr @@ -18,19 +18,20 @@ help: consider relaxing the implicit `Sized` restriction LL | trait Bar<T: ?Sized> { | ++++++++ -error[E0038]: the trait `Baz` cannot be made into an object - --> $DIR/supertrait-mentions-Self.rs:16:31 +error[E0038]: the trait `Baz` is not dyn compatible + --> $DIR/supertrait-mentions-Self.rs:16:35 | LL | fn make_baz<T:Baz>(t: &T) -> &dyn Baz { - | ^^^^^^^ `Baz` cannot be made into an object + | ^^^ `Baz` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/supertrait-mentions-Self.rs:8:13 | LL | trait Baz : Bar<Self> { | --- ^^^^^^^^^ ...because it uses `Self` as a type parameter | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... help: consider using an opaque type instead | LL | fn make_baz<T:Baz>(t: &T) -> &impl Baz { diff --git a/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr b/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr index ef0abc16342..8442314835e 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr +++ b/tests/ui/dyn-compatibility/taint-const-eval.curr.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Qux` cannot be made into an object +error[E0038]: the trait `Qux` is not dyn compatible --> $DIR/taint-const-eval.rs:11:15 | LL | static FOO: &(dyn Qux + Sync) = "desc"; - | ^^^^^^^^^^^^^^ `Qux` cannot be made into an object + | ^^^^^^^^^^^^^^ `Qux` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/taint-const-eval.rs:8:8 | LL | trait Qux { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar(); | ^^^ ...because associated function `bar` has no `self` parameter help: consider turning `bar` into a method by giving it a `&self` argument @@ -20,17 +21,18 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o LL | fn bar() where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Qux` cannot be made into an object +error[E0038]: the trait `Qux` is not dyn compatible --> $DIR/taint-const-eval.rs:11:33 | LL | static FOO: &(dyn Qux + Sync) = "desc"; - | ^^^^^^ `Qux` cannot be made into an object + | ^^^^^^ `Qux` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/taint-const-eval.rs:8:8 | LL | trait Qux { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar(); | ^^^ ...because associated function `bar` has no `self` parameter = note: required for the cast from `&'static str` to `&'static (dyn Qux + Sync + 'static)` @@ -43,17 +45,18 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o LL | fn bar() where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Qux` cannot be made into an object +error[E0038]: the trait `Qux` is not dyn compatible --> $DIR/taint-const-eval.rs:11:15 | LL | static FOO: &(dyn Qux + Sync) = "desc"; - | ^^^^^^^^^^^^^^ `Qux` cannot be made into an object + | ^^^^^^^^^^^^^^ `Qux` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/taint-const-eval.rs:8:8 | LL | trait Qux { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar(); | ^^^ ...because associated function `bar` has no `self` parameter = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` diff --git a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr b/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr index 14940365d23..1c51df8501f 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/dyn-compatibility/taint-const-eval.dyn_compatible_for_dispatch.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Qux` cannot be made into an object +error[E0038]: the trait `Qux` is not dyn compatible --> $DIR/taint-const-eval.rs:11:33 | LL | static FOO: &(dyn Qux + Sync) = "desc"; - | ^^^^^^ `Qux` cannot be made into an object + | ^^^^^^ `Qux` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/taint-const-eval.rs:8:8 | LL | trait Qux { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar(); | ^^^ ...because associated function `bar` has no `self` parameter = note: required for the cast from `&'static str` to `&'static (dyn Qux + Sync + 'static)` diff --git a/tests/ui/dyn-compatibility/taint-const-eval.rs b/tests/ui/dyn-compatibility/taint-const-eval.rs index 9825ec0ca1c..2feae58080b 100644 --- a/tests/ui/dyn-compatibility/taint-const-eval.rs +++ b/tests/ui/dyn-compatibility/taint-const-eval.rs @@ -9,8 +9,8 @@ trait Qux { } static FOO: &(dyn Qux + Sync) = "desc"; -//~^ the trait `Qux` cannot be made into an object -//[curr]~| the trait `Qux` cannot be made into an object -//[curr]~| the trait `Qux` cannot be made into an object +//~^ the trait `Qux` is not dyn compatible +//[curr]~| the trait `Qux` is not dyn compatible +//[curr]~| the trait `Qux` is not dyn compatible fn main() {} diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs index 5c71bd7769c..ec32bec7785 100644 --- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs +++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.rs @@ -17,13 +17,13 @@ pub trait Fetcher: Send + Sync { } fn fetcher() -> Box<dyn Fetcher> { - //~^ ERROR the trait `Fetcher` cannot be made into an object + //~^ ERROR the trait `Fetcher` is not dyn compatible todo!() } pub fn foo() { let fetcher = fetcher(); - //~^ ERROR the trait `Fetcher` cannot be made into an object + //~^ ERROR the trait `Fetcher` is not dyn compatible let _ = fetcher.get(); - //~^ ERROR the trait `Fetcher` cannot be made into an object + //~^ ERROR the trait `Fetcher` is not dyn compatible } diff --git a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr index 8d62ac9d923..45a924008c7 100644 --- a/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr +++ b/tests/ui/dyn-compatibility/undispatchable-receiver-and-wc-references-Self.stderr @@ -1,51 +1,54 @@ -error[E0038]: the trait `Fetcher` cannot be made into an object +error[E0038]: the trait `Fetcher` is not dyn compatible --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:19:21 | LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>> | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` ... LL | fn fetcher() -> Box<dyn Fetcher> { - | ^^^^^^^^^^^ `Fetcher` cannot be made into an object + | ^^^^^^^^^^^ `Fetcher` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 | LL | pub trait Fetcher: Send + Sync { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>> | ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on -error[E0038]: the trait `Fetcher` cannot be made into an object +error[E0038]: the trait `Fetcher` is not dyn compatible --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:25:19 | LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>> | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` ... LL | let fetcher = fetcher(); - | ^^^^^^^^^ `Fetcher` cannot be made into an object + | ^^^^^^^^^ `Fetcher` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 | LL | pub trait Fetcher: Send + Sync { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>> | ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on -error[E0038]: the trait `Fetcher` cannot be made into an object +error[E0038]: the trait `Fetcher` is not dyn compatible --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:27:13 | LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>> | ------------- help: consider changing method `get`'s `self` parameter to be `&self`: `&Self` ... LL | let _ = fetcher.get(); - | ^^^^^^^^^^^^^ `Fetcher` cannot be made into an object + | ^^^^^^^^^^^^^ `Fetcher` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/undispatchable-receiver-and-wc-references-Self.rs:11:22 | LL | pub trait Fetcher: Send + Sync { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | fn get<'a>(self: &'a Box<Self>) -> Pin<Box<dyn Future<Output = Vec<u8>> + 'a>> | ^^^^^^^^^^^^^ ...because method `get`'s `self` parameter cannot be dispatched on diff --git a/tests/ui/error-codes/E0038.stderr b/tests/ui/error-codes/E0038.stderr index 54b489c655f..59e9f504d17 100644 --- a/tests/ui/error-codes/E0038.stderr +++ b/tests/ui/error-codes/E0038.stderr @@ -1,29 +1,31 @@ -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/E0038.rs:5:20 | LL | fn call_foo(x: Box<dyn Trait>) { - | ^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/E0038.rs:2:22 | LL | trait Trait { - | ----- this trait cannot be made into an object... + | ----- this trait is not dyn compatible... LL | fn foo(&self) -> Self; | ^^^^ ...because method `foo` references the `Self` type in its return type = help: consider moving `foo` to another trait -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/E0038.rs:7:13 | LL | let y = x.foo(); - | ^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/E0038.rs:2:22 | LL | trait Trait { - | ----- this trait cannot be made into an object... + | ----- this trait is not dyn compatible... LL | fn foo(&self) -> Self; | ^^^^ ...because method `foo` references the `Self` type in its return type = help: consider moving `foo` to another trait diff --git a/tests/ui/error-codes/E0132.rs b/tests/ui/error-codes/E0132.rs deleted file mode 100644 index fb5e5d7b95a..00000000000 --- a/tests/ui/error-codes/E0132.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(start)] - -#[start] -fn f< T >() {} //~ ERROR E0132 - -fn main() { -} diff --git a/tests/ui/error-codes/E0132.stderr b/tests/ui/error-codes/E0132.stderr deleted file mode 100644 index b1990afa3ae..00000000000 --- a/tests/ui/error-codes/E0132.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0132]: `#[start]` function is not allowed to have type parameters - --> $DIR/E0132.rs:4:5 - | -LL | fn f< T >() {} - | ^^^^^ `#[start]` function cannot have type parameters - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0132`. diff --git a/tests/ui/error-codes/E0138.rs b/tests/ui/error-codes/E0138.rs deleted file mode 100644 index 6f3c36282e8..00000000000 --- a/tests/ui/error-codes/E0138.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(start)] - -#[start] -fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } - -#[start] -fn f(argc: isize, argv: *const *const u8) -> isize { 0 } -//~^ ERROR E0138 diff --git a/tests/ui/error-codes/E0138.stderr b/tests/ui/error-codes/E0138.stderr deleted file mode 100644 index 04877ab4082..00000000000 --- a/tests/ui/error-codes/E0138.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0138]: multiple `start` functions - --> $DIR/E0138.rs:7:1 - | -LL | fn foo(argc: isize, argv: *const *const u8) -> isize { 0 } - | ---------------------------------------------------- previous `#[start]` function here -... -LL | fn f(argc: isize, argv: *const *const u8) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ multiple `start` functions - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0138`. diff --git a/tests/ui/error-codes/E0225.stderr b/tests/ui/error-codes/E0225.stderr index a4b33a0b7b4..e6781282c8f 100644 --- a/tests/ui/error-codes/E0225.stderr +++ b/tests/ui/error-codes/E0225.stderr @@ -20,8 +20,8 @@ LL | trait Foo = std::io::Read + std::io::Write; LL | let _: Box<dyn Foo>; | ^^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: std::io::Read + std::io::Write {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> diff --git a/tests/ui/error-codes/E0451.stderr b/tests/ui/error-codes/E0451.stderr index 419cf117efe..2cd30095c80 100644 --- a/tests/ui/error-codes/E0451.stderr +++ b/tests/ui/error-codes/E0451.stderr @@ -8,7 +8,7 @@ error[E0451]: field `b` of struct `Foo` is private --> $DIR/E0451.rs:18:29 | LL | let f = bar::Foo{ a: 0, b: 0 }; - | ^^^^ private field + | ^ private field error: aborting due to 2 previous errors diff --git a/tests/ui/error-codes/E0647.rs b/tests/ui/error-codes/E0647.rs deleted file mode 100644 index fc085511cbc..00000000000 --- a/tests/ui/error-codes/E0647.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![no_std] -#![feature(start)] - -extern crate std; - -#[start] -fn start(_: isize, _: *const *const u8) -> isize where (): Copy { //~ ERROR [E0647] - 0 -} diff --git a/tests/ui/error-codes/E0647.stderr b/tests/ui/error-codes/E0647.stderr deleted file mode 100644 index 4b444e5a397..00000000000 --- a/tests/ui/error-codes/E0647.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0647]: `#[start]` function is not allowed to have a `where` clause - --> $DIR/E0647.rs:7:50 - | -LL | fn start(_: isize, _: *const *const u8) -> isize where (): Copy { - | ^^^^^^^^^^^^^^ `#[start]` function cannot have a `where` clause - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0647`. diff --git a/tests/ui/expr/if/if-let.stderr b/tests/ui/expr/if/if-let.stderr index c4bba3cb1a8..792504a9772 100644 --- a/tests/ui/expr/if/if-let.stderr +++ b/tests/ui/expr/if/if-let.stderr @@ -2,7 +2,7 @@ warning: irrefutable `if let` pattern --> $DIR/if-let.rs:6:16 | LL | if let $p = $e $b - | ^^^ + | ^^^^^^^^^^^ ... LL | / foo!(a, 1, { LL | | println!("irrefutable pattern"); diff --git a/tests/ui/extern/extern-prelude-core.rs b/tests/ui/extern/extern-prelude-core.rs index ced1e5c3915..5108c02517c 100644 --- a/tests/ui/extern/extern-prelude-core.rs +++ b/tests/ui/extern/extern-prelude-core.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(lang_items, start)] +#![feature(lang_items)] #![no_std] extern crate std as other; @@ -11,8 +11,6 @@ mod foo { } } -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { +fn main() { foo::test(); - 0 } diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs index d9ff45f57ec..278a5451e84 100644 --- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs +++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs @@ -5,10 +5,10 @@ trait Foo { } async fn takes_dyn_trait(x: &dyn Foo) { - //~^ ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible x.bar().await; - //~^ ERROR the trait `Foo` cannot be made into an object - //~| ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible + //~| ERROR the trait `Foo` is not dyn compatible } fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr index f78fc422410..b4de6b66469 100644 --- a/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr +++ b/tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.stderr @@ -1,44 +1,47 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:7:30 | LL | async fn takes_dyn_trait(x: &dyn Foo) { - | ^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | async fn bar(&self); | ^^^ ...because method `bar` is `async` = help: consider moving `bar` to another trait -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:7 | LL | x.bar().await; - | ^^^ `Foo` cannot be made into an object + | ^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | async fn bar(&self); | ^^^ ...because method `bar` is `async` = help: consider moving `bar` to another trait -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:5 | LL | x.bar().await; - | ^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | async fn bar(&self); | ^^^ ...because method `bar` is `async` = help: consider moving `bar` to another trait diff --git a/tests/ui/feature-gates/feature-gate-default-field-values.stderr b/tests/ui/feature-gates/feature-gate-default-field-values.stderr index d882c322c8e..104d72a3986 100644 --- a/tests/ui/feature-gates/feature-gate-default-field-values.stderr +++ b/tests/ui/feature-gates/feature-gate-default-field-values.stderr @@ -130,7 +130,10 @@ error[E0797]: base expression required after `..` LL | let x = Foo { .. }; | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | let x = Foo { ../* expr */ }; @@ -142,7 +145,10 @@ error[E0797]: base expression required after `..` LL | let z = Foo { baz: 1, .. }; | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | let z = Foo { baz: 1, ../* expr */ }; @@ -154,7 +160,10 @@ error[E0797]: base expression required after `..` LL | let x = Bar::Foo { .. }; | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | let x = Bar::Foo { ../* expr */ }; @@ -166,7 +175,10 @@ error[E0797]: base expression required after `..` LL | let z = Bar::Foo { baz: 1, .. }; | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | let z = Bar::Foo { baz: 1, ../* expr */ }; @@ -178,7 +190,10 @@ error[E0797]: base expression required after `..` LL | let x = Qux::<i32, 4> { .. }; | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | let x = Qux::<i32, 4> { ../* expr */ }; @@ -190,7 +205,10 @@ error[E0797]: base expression required after `..` LL | assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, .. }, x)); | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | assert!(matches!(Qux::<i32, 4> { bar: S, baz: 42, bat: 2, bay: 4, ../* expr */ }, x)); @@ -202,7 +220,10 @@ error[E0797]: base expression required after `..` LL | let y = Opt { mandatory: None, .. }; | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | let y = Opt { mandatory: None, ../* expr */ }; @@ -214,7 +235,10 @@ error[E0797]: base expression required after `..` LL | assert!(matches!(Opt { mandatory: None, .. }, z)); | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | assert!(matches!(Opt { mandatory: None, ../* expr */ }, z)); @@ -260,7 +284,10 @@ error[E0797]: base expression required after `..` LL | let y = OptEnum::Variant { mandatory: None, .. }; | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | let y = OptEnum::Variant { mandatory: None, ../* expr */ }; @@ -272,7 +299,10 @@ error[E0797]: base expression required after `..` LL | assert!(matches!(OptEnum::Variant { mandatory: None, .. }, z)); | ^ | - = help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | help: add a base expression here | LL | assert!(matches!(OptEnum::Variant { mandatory: None, ../* expr */ }, z)); diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs index 3c9e903d4ba..37eabbf1602 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.rs @@ -30,6 +30,6 @@ impl Trait for i32 { fn main() { Ptr(Box::new(4)) as Ptr<dyn Trait>; - //~^ ERROR the trait `Trait` cannot be made into an object - //~^^ ERROR the trait `Trait` cannot be made into an object + //~^ ERROR the trait `Trait` is not dyn compatible + //~^^ ERROR the trait `Trait` is not dyn compatible } diff --git a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr index 28caaf8356f..f8fc086c441 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr @@ -1,38 +1,40 @@ -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:25 | LL | fn ptr(self: Ptr<Self>); | --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self` ... LL | Ptr(Box::new(4)) as Ptr<dyn Trait>; - | ^^^^^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 | LL | trait Trait { - | ----- this trait cannot be made into an object... + | ----- this trait is not dyn compatible... LL | fn ptr(self: Ptr<Self>); | ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on - = help: only type `i32` implements the trait, consider using it directly instead + = help: only type `i32` implements `Trait`; consider using it directly instead. -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:32:5 | LL | fn ptr(self: Ptr<Self>); | --------- help: consider changing method `ptr`'s `self` parameter to be `&self`: `&Self` ... LL | Ptr(Box::new(4)) as Ptr<dyn Trait>; - | ^^^^^^^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:25:18 | LL | trait Trait { - | ----- this trait cannot be made into an object... + | ----- this trait is not dyn compatible... LL | fn ptr(self: Ptr<Self>); | ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on - = help: only type `i32` implements the trait, consider using it directly instead + = help: only type `i32` implements `Trait`; consider using it directly instead. = note: required for the cast from `Ptr<{integer}>` to `Ptr<dyn Trait>` error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr index ed021c154a5..10540f0219d 100644 --- a/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr +++ b/tests/ui/feature-gates/feature-gate-dyn_compatible_for_dispatch.stderr @@ -1,28 +1,30 @@ -error[E0038]: the trait `DynIncompatible1` cannot be made into an object +error[E0038]: the trait `DynIncompatible1` is not dyn compatible --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:18:40 | LL | fn takes_dyn_incompatible_ref<T>(obj: &dyn DynIncompatible1) { - | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25 | LL | trait DynIncompatible1: Sized {} | ---------------- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... -error[E0038]: the trait `DynIncompatible2` cannot be made into an object +error[E0038]: the trait `DynIncompatible2` is not dyn compatible --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:22:46 | LL | fn return_dyn_incompatible_ref() -> &'static dyn DynIncompatible2 { - | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible2` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible2` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:7:8 | LL | trait DynIncompatible2 { - | ---------------- this trait cannot be made into an object... + | ---------------- this trait is not dyn compatible... LL | fn static_fn() {} | ^^^^^^^^^ ...because associated function `static_fn` has no `self` parameter help: consider turning `static_fn` into a method by giving it a `&self` argument @@ -34,49 +36,52 @@ help: alternatively, consider constraining `static_fn` so it does not apply to t LL | fn static_fn() where Self: Sized {} | +++++++++++++++++ -error[E0038]: the trait `DynIncompatible3` cannot be made into an object +error[E0038]: the trait `DynIncompatible3` is not dyn compatible --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:27:40 | LL | fn takes_dyn_incompatible_box(obj: Box<dyn DynIncompatible3>) { - | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible3` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible3` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:11:8 | LL | trait DynIncompatible3 { - | ---------------- this trait cannot be made into an object... + | ---------------- this trait is not dyn compatible... LL | fn foo<T>(&self); | ^^^ ...because method `foo` has generic type parameters = help: consider moving `foo` to another trait -error[E0038]: the trait `DynIncompatible4` cannot be made into an object +error[E0038]: the trait `DynIncompatible4` is not dyn compatible --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:31:48 | LL | fn return_dyn_incompatible_rc() -> std::rc::Rc<dyn DynIncompatible4> { - | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible4` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible4` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:15:22 | LL | trait DynIncompatible4 { - | ---------------- this trait cannot be made into an object... + | ---------------- this trait is not dyn compatible... LL | fn foo(&self, s: &Self); | ^^^^^ ...because method `foo` references the `Self` type in this parameter = help: consider moving `foo` to another trait -error[E0038]: the trait `DynIncompatible1` cannot be made into an object +error[E0038]: the trait `DynIncompatible1` is not dyn compatible --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:38:16 | LL | impl Trait for dyn DynIncompatible1 {} - | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `DynIncompatible1` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/feature-gate-dyn_compatible_for_dispatch.rs:4:25 | LL | trait DynIncompatible1: Sized {} | ---------------- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... error: aborting due to 5 previous errors diff --git a/tests/ui/feature-gates/feature-gate-start.rs b/tests/ui/feature-gates/feature-gate-start.rs deleted file mode 100644 index e617f1c4759..00000000000 --- a/tests/ui/feature-gates/feature-gate-start.rs +++ /dev/null @@ -1,3 +0,0 @@ -#[start] -fn foo(_: isize, _: *const *const u8) -> isize { 0 } -//~^ ERROR `#[start]` functions are experimental diff --git a/tests/ui/feature-gates/feature-gate-start.stderr b/tests/ui/feature-gates/feature-gate-start.stderr deleted file mode 100644 index b1859c43718..00000000000 --- a/tests/ui/feature-gates/feature-gate-start.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0658]: `#[start]` functions are experimental and their signature may change over time - --> $DIR/feature-gate-start.rs:2:1 - | -LL | fn foo(_: isize, _: *const *const u8) -> isize { 0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #29633 <https://github.com/rust-lang/rust/issues/29633> for more information - = help: add `#![feature(start)]` 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/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs index afffb3b1443..02a56c7e6aa 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs @@ -14,8 +14,6 @@ #![rustc_main] //~ ERROR: the `#[rustc_main]` attribute is used internally to specify //~^ ERROR: `rustc_main` attribute cannot be used at crate level //~| NOTE: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -#![start] -//~^ ERROR: `start` attribute cannot be used at crate level #![repr()] //~^ ERROR: `repr` attribute cannot be used at crate level #![path = "3800"] @@ -38,7 +36,6 @@ mod inline { //~| NOTE the inner attribute doesn't annotate this module //~| NOTE the inner attribute doesn't annotate this module //~| NOTE the inner attribute doesn't annotate this module - //~| NOTE the inner attribute doesn't annotate this module mod inner { #![inline] } //~^ ERROR attribute should be applied to function or closure @@ -123,24 +120,6 @@ mod export_name { } } -#[start] -//~^ ERROR: `start` attribute can only be used on functions -mod start { - mod inner { #![start] } - //~^ ERROR: `start` attribute can only be used on functions - - // for `fn f()` case, see feature-gate-start.rs - - #[start] struct S; - //~^ ERROR: `start` attribute can only be used on functions - - #[start] type T = S; - //~^ ERROR: `start` attribute can only be used on functions - - #[start] impl S { } - //~^ ERROR: `start` attribute can only be used on functions -} - #[repr(C)] //~^ ERROR: attribute should be applied to a struct, enum, or union mod repr { diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index db8c5295a2d..648bafe6460 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -8,7 +8,7 @@ LL | #![rustc_main] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]` - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:47:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5 | LL | #[inline = "2100"] fn f() { } | ^^^^^^^^^^^^^^^^^^ @@ -17,38 +17,8 @@ LL | #[inline = "2100"] fn f() { } = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571> = note: `#[deny(ill_formed_attribute_input)]` on by default -error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:126:1 - | -LL | #[start] - | ^^^^^^^^ - -error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:129:17 - | -LL | mod inner { #![start] } - | ^^^^^^^^^ - -error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:134:5 - | -LL | #[start] struct S; - | ^^^^^^^^ - -error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:5 - | -LL | #[start] type T = S; - | ^^^^^^^^ - -error: `start` attribute can only be used on functions - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:140:5 - | -LL | #[start] impl S { } - | ^^^^^^^^ - error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1 | LL | #[inline] | ^^^^^^^^^ @@ -59,7 +29,7 @@ LL | | } | |_- not a function or closure error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:66:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:63:1 | LL | #[no_link] | ^^^^^^^^^^ @@ -73,7 +43,7 @@ LL | | } | |_- not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:92:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:89:1 | LL | #[export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +57,7 @@ LL | | } | |_- not a free function, impl method or static error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:144:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:123:8 | LL | #[repr(C)] | ^ @@ -100,7 +70,7 @@ LL | | } | |_- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:168:8 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:147:8 | LL | #[repr(Rust)] | ^^^^ @@ -113,19 +83,19 @@ LL | | } | |_- not a struct, enum, or union error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:24:1 | LL | #![no_link] | ^^^^^^^^^^^ not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:26:1 | LL | #![export_name = "2200"] | ^^^^^^^^^^^^^^^^^^^^^^^^ not a free function, impl method or static error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:30:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:1 | LL | #![inline] | ^^^^^^^^^^ not a function or closure @@ -160,23 +130,8 @@ LL - #![rustc_main] LL + #[rustc_main] | -error: `start` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1 - | -LL | #![start] - | ^^^^^^^^^ -... -LL | mod inline { - | ------ the inner attribute doesn't annotate this module - | -help: perhaps you meant to use an outer attribute - | -LL - #![start] -LL + #[start] - | - error: `repr` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:17:1 | LL | #![repr()] | ^^^^^^^^^^ @@ -191,7 +146,7 @@ LL + #[repr()] | error: `path` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:19:1 | LL | #![path = "3800"] | ^^^^^^^^^^^^^^^^^ @@ -206,7 +161,7 @@ LL + #[path = "3800"] | error: `automatically_derived` attribute cannot be used at crate level - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:23:1 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:21:1 | LL | #![automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -221,144 +176,144 @@ LL + #[automatically_derived] | error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:43:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:40:17 | LL | mod inner { #![inline] } | ------------^^^^^^^^^^-- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:53:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5 | LL | #[inline] struct S; | ^^^^^^^^^ --------- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:57:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5 | LL | #[inline] type T = S; | ^^^^^^^^^ ----------- not a function or closure error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:61:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5 | LL | #[inline] impl S { } | ^^^^^^^^^ ---------- not a function or closure error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:71:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:68:17 | LL | mod inner { #![no_link] } | ------------^^^^^^^^^^^-- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:75:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:5 | LL | #[no_link] fn f() { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:79:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:76:5 | LL | #[no_link] struct S; | ^^^^^^^^^^ --------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:83:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:80:5 | LL | #[no_link]type T = S; | ^^^^^^^^^^----------- not an `extern crate` item error: attribute should be applied to an `extern crate` item - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:87:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:84:5 | LL | #[no_link] impl S { } | ^^^^^^^^^^ ---------- not an `extern crate` item error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:97:17 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:94:17 | LL | mod inner { #![export_name="2200"] } | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:103:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:100:5 | LL | #[export_name = "2200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:107:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:104:5 | LL | #[export_name = "2200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:111:5 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:108:5 | LL | #[export_name = "2200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:116:9 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:113:9 | LL | #[export_name = "2200"] fn foo(); | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a free function, impl method or static error: attribute should be applied to a free function, impl method or static - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:120:9 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:117:9 | LL | #[export_name = "2200"] fn bar() {} | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a free function, impl method or static error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:148:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:127:25 | LL | mod inner { #![repr(C)] } | --------------------^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:152:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:131:12 | LL | #[repr(C)] fn f() { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:158:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:137:12 | LL | #[repr(C)] type T = S; | ^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:162:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:141:12 | LL | #[repr(C)] impl S { } | ^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:172:25 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:151:25 | LL | mod inner { #![repr(Rust)] } | --------------------^^^^---- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:176:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:155:12 | LL | #[repr(Rust)] fn f() { } | ^^^^ ---------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:182:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:161:12 | LL | #[repr(Rust)] type T = S; | ^^^^ ----------- not a struct, enum, or union error[E0517]: attribute should be applied to a struct, enum, or union - --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:186:12 + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:165:12 | LL | #[repr(Rust)] impl S { } | ^^^^ ---------- not a struct, enum, or union -error: aborting due to 44 previous errors +error: aborting due to 38 previous errors Some errors have detailed explanations: E0517, E0518, E0658. For more information about an error, try `rustc --explain E0517`. diff --git a/tests/ui/for-loop-while/for-loop-no-std.rs b/tests/ui/for-loop-while/for-loop-no-std.rs index 4511146dc75..8255d7b4200 100644 --- a/tests/ui/for-loop-while/for-loop-no-std.rs +++ b/tests/ui/for-loop-while/for-loop-no-std.rs @@ -1,14 +1,19 @@ //@ run-pass +//@ ignore-emscripten no no_std executables +//@ ignore-wasm different `main` convention #![allow(unused_imports)] -#![feature(lang_items, start)] #![no_std] +#![no_main] +// Import global allocator and panic handler. extern crate std as other; #[macro_use] extern crate alloc; -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { +use alloc::string::ToString; + +#[no_mangle] +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { for _ in [1,2,3].iter() { } 0 } diff --git a/tests/ui/for-loop-while/while-let-2.stderr b/tests/ui/for-loop-while/while-let-2.stderr index 1b1cf679243..355ae6f718e 100644 --- a/tests/ui/for-loop-while/while-let-2.stderr +++ b/tests/ui/for-loop-while/while-let-2.stderr @@ -2,7 +2,7 @@ warning: irrefutable `while let` pattern --> $DIR/while-let-2.rs:7:19 | LL | while let $p = $e $b - | ^^^ + | ^^^^^^^^^^^ ... LL | / foo!(_a, 1, { LL | | println!("irrefutable pattern"); diff --git a/tests/ui/format-no-std.rs b/tests/ui/format-no-std.rs index 27c31f48a00..657b210a9a0 100644 --- a/tests/ui/format-no-std.rs +++ b/tests/ui/format-no-std.rs @@ -1,17 +1,20 @@ //@ run-pass //@ ignore-emscripten no no_std executables +//@ ignore-wasm different `main` convention -#![feature(lang_items, start)] +#![feature(lang_items)] #![no_std] +#![no_main] +// Import global allocator and panic handler. extern crate std as other; #[macro_use] extern crate alloc; use alloc::string::ToString; -#[start] -fn start(_argc: isize, _argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int { let s = format!("{}", 1_isize); assert_eq!(s, "1".to_string()); diff --git a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs index 1a4678c7e70..b02739a7d0a 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs +++ b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.rs @@ -8,5 +8,5 @@ fn main() { //~| ERROR: binding for associated type `Y` references lifetime //~| ERROR: binding for associated type `Y` references lifetime //~| ERROR: binding for associated type `Y` references lifetime - //~| ERROR: the trait `X` cannot be made into an object + //~| ERROR: the trait `X` is not dyn compatible } diff --git a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr index 867f55b0dee..4c5a47e73c6 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path-undeclared-lifetime.stderr @@ -36,17 +36,18 @@ LL | fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {} | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:6:19 | LL | fn _f(arg : Box<dyn for<'a> X<Y<'x> = &'a [u32]>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/gat-in-trait-path-undeclared-lifetime.rs:2:8 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'x>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr index 34642f8fdc6..b2b569e6261 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path.base.stderr @@ -1,56 +1,50 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/gat-in-trait-path.rs:26:17 | LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/gat-in-trait-path.rs:10:10 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | type A<'a> where Self: 'a; | ^ ...because it contains the generic associated type `A` = help: consider moving `A` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead: - Fooy - Fooer<T> -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/gat-in-trait-path.rs:32:5 | LL | f(Box::new(foo)); - | ^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/gat-in-trait-path.rs:10:10 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | type A<'a> where Self: 'a; | ^ ...because it contains the generic associated type `A` = help: consider moving `A` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead: - Fooy - Fooer<T> -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/gat-in-trait-path.rs:32:5 | LL | f(Box::new(foo)); - | ^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/gat-in-trait-path.rs:10:10 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | type A<'a> where Self: 'a; | ^ ...because it contains the generic associated type `A` = help: consider moving `A` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead: - Fooy - Fooer<T> = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A<'a> = &'a ()> + 'static)>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.rs b/tests/ui/generic-associated-types/gat-in-trait-path.rs index cd759a73cf2..24cae213e0a 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.rs +++ b/tests/ui/generic-associated-types/gat-in-trait-path.rs @@ -20,12 +20,11 @@ impl<T> Foo for Fooer<T> { } fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {} -//~^ the trait `Foo` cannot be made into an object - +//~^ the trait `Foo` is not dyn compatible fn main() { let foo = Fooer(5); f(Box::new(foo)); - //~^ the trait `Foo` cannot be made into an object - //~| the trait `Foo` cannot be made into an object + //~^ the trait `Foo` is not dyn compatible + //~| the trait `Foo` is not dyn compatible } diff --git a/tests/ui/generic-associated-types/gat-in-trait-path.stderr b/tests/ui/generic-associated-types/gat-in-trait-path.stderr index b2176fa6de3..df79556c825 100644 --- a/tests/ui/generic-associated-types/gat-in-trait-path.stderr +++ b/tests/ui/generic-associated-types/gat-in-trait-path.stderr @@ -1,56 +1,50 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/gat-in-trait-path.rs:22:17 | LL | fn f(_arg : Box<dyn for<'a> Foo<A<'a> = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/gat-in-trait-path.rs:6:10 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | type A<'a> where Self: 'a; | ^ ...because it contains the generic associated type `A` = help: consider moving `A` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead: - Fooy - Fooer<T> -error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/gat-in-trait-path.rs:28:5 +error[E0038]: the trait `Foo` is not dyn compatible + --> $DIR/gat-in-trait-path.rs:27:5 | LL | f(Box::new(foo)); - | ^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/gat-in-trait-path.rs:6:10 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | type A<'a> where Self: 'a; | ^ ...because it contains the generic associated type `A` = help: consider moving `A` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead: - Fooy - Fooer<T> -error[E0038]: the trait `Foo` cannot be made into an object - --> $DIR/gat-in-trait-path.rs:28:5 +error[E0038]: the trait `Foo` is not dyn compatible + --> $DIR/gat-in-trait-path.rs:27:5 | LL | f(Box::new(foo)); - | ^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/gat-in-trait-path.rs:6:10 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | type A<'a> where Self: 'a; | ^ ...because it contains the generic associated type `A` = help: consider moving `A` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Foo` for this new enum and using it instead: - Fooy - Fooer<T> = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A<'a> = &'a ()> + 'static)>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs index c4134427013..85661c1b844 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs @@ -12,7 +12,7 @@ fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {} //~| ERROR associated type takes 0 generic arguments but 1 generic argument //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments //~| ERROR at least one trait is required - //~| ERROR: the trait `X` cannot be made into an object + //~| ERROR: the trait `X` is not dyn compatible fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {} @@ -20,6 +20,6 @@ fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {} //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments - //~| ERROR: the trait `X` cannot be made into an object + //~| ERROR: the trait `X` is not dyn compatible fn main() {} diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr index 97b7019b385..499ce8e4a32 100644 --- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr +++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr @@ -123,17 +123,18 @@ error[E0224]: at least one trait is required for an object type LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {} | ^^ -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/gat-trait-path-parenthesised-args.rs:5:21 | LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'a>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait @@ -188,17 +189,18 @@ help: add missing lifetime argument LL | fn bar<'a>(arg: Box<dyn X<Y('_) = ()>>) {} | ++ -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/gat-trait-path-parenthesised-args.rs:18:21 | LL | fn bar<'a>(arg: Box<dyn X<Y() = ()>>) {} - | ^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/gat-trait-path-parenthesised-args.rs:2:8 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'a>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait diff --git a/tests/ui/generic-associated-types/issue-67510-pass.base.stderr b/tests/ui/generic-associated-types/issue-67510-pass.base.stderr index cac8010018e..56308948969 100644 --- a/tests/ui/generic-associated-types/issue-67510-pass.base.stderr +++ b/tests/ui/generic-associated-types/issue-67510-pass.base.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/issue-67510-pass.rs:12:23 | LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-67510-pass.rs:9:10 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'a>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait diff --git a/tests/ui/generic-associated-types/issue-67510-pass.rs b/tests/ui/generic-associated-types/issue-67510-pass.rs index a48d9c37cd4..2bfba7f6942 100644 --- a/tests/ui/generic-associated-types/issue-67510-pass.rs +++ b/tests/ui/generic-associated-types/issue-67510-pass.rs @@ -5,6 +5,6 @@ trait X { } fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {} -//~^ ERROR the trait `X` cannot be made into an object +//~^ ERROR the trait `X` is not dyn compatible fn main() {} diff --git a/tests/ui/generic-associated-types/issue-67510-pass.stderr b/tests/ui/generic-associated-types/issue-67510-pass.stderr index 5560cb0f64d..f6846f833fe 100644 --- a/tests/ui/generic-associated-types/issue-67510-pass.stderr +++ b/tests/ui/generic-associated-types/issue-67510-pass.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/issue-67510-pass.rs:7:23 | LL | fn _func1<'a>(_x: Box<dyn X<Y<'a>=&'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-67510-pass.rs:4:10 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'a>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait diff --git a/tests/ui/generic-associated-types/issue-67510.rs b/tests/ui/generic-associated-types/issue-67510.rs index ab5c25d74da..5c3150a77ed 100644 --- a/tests/ui/generic-associated-types/issue-67510.rs +++ b/tests/ui/generic-associated-types/issue-67510.rs @@ -5,6 +5,6 @@ trait X { fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {} //~^ ERROR: use of undeclared lifetime name `'a` //~| ERROR: use of undeclared lifetime name `'a` -//~| ERROR: the trait `X` cannot be made into an object [E0038] +//~| ERROR: the trait `X` is not dyn compatible [E0038] fn main() {} diff --git a/tests/ui/generic-associated-types/issue-67510.stderr b/tests/ui/generic-associated-types/issue-67510.stderr index 416f04ac2fd..e8555a7aa1f 100644 --- a/tests/ui/generic-associated-types/issue-67510.stderr +++ b/tests/ui/generic-associated-types/issue-67510.stderr @@ -29,17 +29,18 @@ help: consider introducing lifetime `'a` here LL | fn f<'a>(x: Box<dyn X<Y<'a> = &'a ()>>) {} | ++++ -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/issue-67510.rs:5:13 | LL | fn f(x: Box<dyn X<Y<'a> = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-67510.rs:2:10 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'a>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait diff --git a/tests/ui/generic-associated-types/issue-71176.rs b/tests/ui/generic-associated-types/issue-71176.rs index 7fffe312f4b..d3a0caffec1 100644 --- a/tests/ui/generic-associated-types/issue-71176.rs +++ b/tests/ui/generic-associated-types/issue-71176.rs @@ -11,13 +11,13 @@ struct Holder<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 + //~| ERROR: the trait `Provider` is not dyn compatible } fn main() { Holder { inner: Box::new(()), - //~^ ERROR: the trait `Provider` cannot be made into an object - //~| ERROR: the trait `Provider` cannot be made into an object + //~^ ERROR: the trait `Provider` is not dyn compatible + //~| ERROR: the trait `Provider` is not dyn compatible }; } diff --git a/tests/ui/generic-associated-types/issue-71176.stderr b/tests/ui/generic-associated-types/issue-71176.stderr index 1cd2ed0d313..a78151384d4 100644 --- a/tests/ui/generic-associated-types/issue-71176.stderr +++ b/tests/ui/generic-associated-types/issue-71176.stderr @@ -48,53 +48,56 @@ help: add missing lifetime argument LL | inner: Box<dyn Provider<A<'a> = B>>, | ++++ -error[E0038]: the trait `Provider` cannot be made into an object +error[E0038]: the trait `Provider` is not dyn compatible --> $DIR/issue-71176.rs:10:14 | LL | inner: Box<dyn Provider<A = B>>, - | ^^^^^^^^^^^^^^^^^^^ `Provider` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `Provider` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + 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... + | -------- this trait is not dyn compatible... 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 + = help: only type `()` implements `Provider`; consider using it directly instead. -error[E0038]: the trait `Provider` cannot be made into an object +error[E0038]: the trait `Provider` is not dyn compatible --> $DIR/issue-71176.rs:19:16 | LL | inner: Box::new(()), - | ^^^^^^^^^^^^ `Provider` cannot be made into an object + | ^^^^^^^^^^^^ `Provider` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + 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... + | -------- this trait is not dyn compatible... 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 + = help: only type `()` implements `Provider`; consider using it directly instead. -error[E0038]: the trait `Provider` cannot be made into an object +error[E0038]: the trait `Provider` is not dyn compatible --> $DIR/issue-71176.rs:19:16 | LL | inner: Box::new(()), - | ^^^^^^^^^^^^ `Provider` cannot be made into an object + | ^^^^^^^^^^^^ `Provider` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + 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... + | -------- this trait is not dyn compatible... 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 + = help: only type `()` implements `Provider`; consider using it directly instead. = note: required for the cast from `Box<()>` to `Box<(dyn Provider<A<'_> = _> + 'static), {type error}>` error: aborting due to 6 previous errors diff --git a/tests/ui/generic-associated-types/issue-76535.base.stderr b/tests/ui/generic-associated-types/issue-76535.base.stderr index a44c8dc51e7..b503fad2d84 100644 --- a/tests/ui/generic-associated-types/issue-76535.base.stderr +++ b/tests/ui/generic-associated-types/issue-76535.base.stderr @@ -14,39 +14,41 @@ help: add missing lifetime argument LL | let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0)); | ++++ -error[E0038]: the trait `SuperTrait` cannot be made into an object +error[E0038]: the trait `SuperTrait` is not dyn compatible --> $DIR/issue-76535.rs:39:14 | LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-76535.rs:9:10 | LL | pub trait SuperTrait { - | ---------- this trait cannot be made into an object... + | ---------- this trait is not dyn compatible... LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ ...because it contains the generic associated type `SubType` = help: consider moving `SubType` to another trait - = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead - = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type + = help: only type `SuperStruct` implements `SuperTrait` within this crate. Consider using it directly instead. + = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type -error[E0038]: the trait `SuperTrait` cannot be made into an object +error[E0038]: the trait `SuperTrait` is not dyn compatible --> $DIR/issue-76535.rs:39:57 | LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-76535.rs:9:10 | LL | pub trait SuperTrait { - | ---------- this trait cannot be made into an object... + | ---------- this trait is not dyn compatible... LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ ...because it contains the generic associated type `SubType` = help: consider moving `SubType` to another trait - = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead - = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type + = help: only type `SuperStruct` implements `SuperTrait` within this crate. Consider using it directly instead. + = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type = note: required for the cast from `Box<SuperStruct>` to `Box<dyn SuperTrait<SubType<'_> = SubStruct<'_>>>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/issue-76535.stderr b/tests/ui/generic-associated-types/issue-76535.stderr index 613ded6f1ef..6b7c3bfe731 100644 --- a/tests/ui/generic-associated-types/issue-76535.stderr +++ b/tests/ui/generic-associated-types/issue-76535.stderr @@ -14,39 +14,41 @@ help: add missing lifetime argument LL | let sub: Box<dyn SuperTrait<SubType<'a> = SubStruct>> = Box::new(SuperStruct::new(0)); | ++++ -error[E0038]: the trait `SuperTrait` cannot be made into an object +error[E0038]: the trait `SuperTrait` is not dyn compatible --> $DIR/issue-76535.rs:34:14 | LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-76535.rs:4:10 | LL | pub trait SuperTrait { - | ---------- this trait cannot be made into an object... + | ---------- this trait is not dyn compatible... LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ ...because it contains the generic associated type `SubType` = help: consider moving `SubType` to another trait - = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead - = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type + = help: only type `SuperStruct` implements `SuperTrait` within this crate; consider using it directly instead. + = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type -error[E0038]: the trait `SuperTrait` cannot be made into an object +error[E0038]: the trait `SuperTrait` is not dyn compatible --> $DIR/issue-76535.rs:34:57 | LL | let sub: Box<dyn SuperTrait<SubType = SubStruct>> = Box::new(SuperStruct::new(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `SuperTrait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-76535.rs:4:10 | LL | pub trait SuperTrait { - | ---------- this trait cannot be made into an object... + | ---------- this trait is not dyn compatible... LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ ...because it contains the generic associated type `SubType` = help: consider moving `SubType` to another trait - = help: only type `SuperStruct` is seen to implement the trait in this crate, consider using it directly instead - = note: `SuperTrait` can be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type + = help: only type `SuperStruct` implements `SuperTrait` within this crate; consider using it directly instead. + = note: `SuperTrait` may be implemented in other crates; if you want to support your users passing their own types here, you can't refer to a specific type = note: required for the cast from `Box<SuperStruct>` to `Box<dyn SuperTrait<SubType<'_> = SubStruct<'_>>>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/issue-78671.base.stderr b/tests/ui/generic-associated-types/issue-78671.base.stderr index 9f2be785460..9bfe8c0b956 100644 --- a/tests/ui/generic-associated-types/issue-78671.base.stderr +++ b/tests/ui/generic-associated-types/issue-78671.base.stderr @@ -14,17 +14,18 @@ help: add missing generic argument LL | Box::new(Family) as &dyn CollectionFamily<Member<T>=usize> | +++ -error[E0038]: the trait `CollectionFamily` cannot be made into an object +error[E0038]: the trait `CollectionFamily` is not dyn compatible --> $DIR/issue-78671.rs:10:25 | LL | Box::new(Family) as &dyn CollectionFamily<Member=usize> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-78671.rs:7:10 | LL | trait CollectionFamily { - | ---------------- this trait cannot be made into an object... + | ---------------- this trait is not dyn compatible... LL | type Member<T>; | ^^^^^^ ...because it contains the generic associated type `Member` = help: consider moving `Member` to another trait diff --git a/tests/ui/generic-associated-types/issue-78671.rs b/tests/ui/generic-associated-types/issue-78671.rs index 0871def1731..1e1863799a5 100644 --- a/tests/ui/generic-associated-types/issue-78671.rs +++ b/tests/ui/generic-associated-types/issue-78671.rs @@ -4,7 +4,7 @@ trait CollectionFamily { fn floatify() { Box::new(Family) as &dyn CollectionFamily<Member=usize> //~^ ERROR: missing generics for associated type - //~| ERROR: the trait `CollectionFamily` cannot be made into an object + //~| ERROR: the trait `CollectionFamily` is not dyn compatible } struct Family; diff --git a/tests/ui/generic-associated-types/issue-78671.stderr b/tests/ui/generic-associated-types/issue-78671.stderr index fbd76c73895..c85e97067cb 100644 --- a/tests/ui/generic-associated-types/issue-78671.stderr +++ b/tests/ui/generic-associated-types/issue-78671.stderr @@ -14,17 +14,18 @@ help: add missing generic argument LL | Box::new(Family) as &dyn CollectionFamily<Member<T>=usize> | +++ -error[E0038]: the trait `CollectionFamily` cannot be made into an object +error[E0038]: the trait `CollectionFamily` is not dyn compatible --> $DIR/issue-78671.rs:5:25 | LL | Box::new(Family) as &dyn CollectionFamily<Member=usize> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `CollectionFamily` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-78671.rs:2:10 | LL | trait CollectionFamily { - | ---------------- this trait cannot be made into an object... + | ---------------- this trait is not dyn compatible... LL | type Member<T>; | ^^^^^^ ...because it contains the generic associated type `Member` = help: consider moving `Member` to another trait diff --git a/tests/ui/generic-associated-types/issue-79422.base.stderr b/tests/ui/generic-associated-types/issue-79422.base.stderr index 3ea62bdbb27..c3de2b71762 100644 --- a/tests/ui/generic-associated-types/issue-79422.base.stderr +++ b/tests/ui/generic-associated-types/issue-79422.base.stderr @@ -14,41 +14,37 @@ help: add missing lifetime argument LL | as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>; | ++++ -error[E0038]: the trait `MapLike` cannot be made into an object +error[E0038]: the trait `MapLike` is not dyn compatible --> $DIR/issue-79422.rs:47:12 | LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-79422.rs:23:10 | LL | trait MapLike<K, V> { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` = help: consider moving `VRefCont` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead: - std::collections::BTreeMap<K, V> - Source -error[E0038]: the trait `MapLike` cannot be made into an object +error[E0038]: the trait `MapLike` is not dyn compatible --> $DIR/issue-79422.rs:44:13 | LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-79422.rs:23:10 | LL | trait MapLike<K, V> { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` = help: consider moving `VRefCont` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead: - std::collections::BTreeMap<K, V> - Source = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont<'_> = (dyn RefCont<'_, u8> + 'static)>>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/issue-79422.stderr b/tests/ui/generic-associated-types/issue-79422.stderr index 26567e5e927..a81217e96c3 100644 --- a/tests/ui/generic-associated-types/issue-79422.stderr +++ b/tests/ui/generic-associated-types/issue-79422.stderr @@ -14,41 +14,37 @@ help: add missing lifetime argument LL | as Box<dyn MapLike<u8, u8, VRefCont<'a> = dyn RefCont<'_, u8>>>; | ++++ -error[E0038]: the trait `MapLike` cannot be made into an object +error[E0038]: the trait `MapLike` is not dyn compatible --> $DIR/issue-79422.rs:41:12 | LL | as Box<dyn MapLike<u8, u8, VRefCont = dyn RefCont<'_, u8>>>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-79422.rs:18:10 | LL | trait MapLike<K, V> { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` = help: consider moving `VRefCont` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead: - std::collections::BTreeMap<K, V> - Source -error[E0038]: the trait `MapLike` cannot be made into an object +error[E0038]: the trait `MapLike` is not dyn compatible --> $DIR/issue-79422.rs:39:13 | LL | let m = Box::new(std::collections::BTreeMap::<u8, u8>::new()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `MapLike` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-79422.rs:18:10 | LL | trait MapLike<K, V> { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` = help: consider moving `VRefCont` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `MapLike` for this new enum and using it instead: - std::collections::BTreeMap<K, V> - Source = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont<'_> = (dyn RefCont<'_, u8> + 'static)>>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.rs b/tests/ui/generic-associated-types/missing_lifetime_args.rs index 470db5412b2..e0f2db5eb21 100644 --- a/tests/ui/generic-associated-types/missing_lifetime_args.rs +++ b/tests/ui/generic-associated-types/missing_lifetime_args.rs @@ -12,7 +12,7 @@ fn foo<'c, 'd>(_arg: Box<dyn X<Y = (&'c u32, &'d u32)>>) {} //~^ ERROR missing generics for associated type //~| ERROR missing generics for associated type //~| ERROR missing generics for associated type -//~| ERROR the trait `X` cannot be made into an object +//~| ERROR the trait `X` is not dyn compatible fn bar<'a, 'b, 'c>(_arg: Foo<'a, 'b>) {} //~^ ERROR struct takes 3 lifetime arguments but 2 lifetime diff --git a/tests/ui/generic-associated-types/missing_lifetime_args.stderr b/tests/ui/generic-associated-types/missing_lifetime_args.stderr index 61cf4f3dd4a..6b8df5cc12f 100644 --- a/tests/ui/generic-associated-types/missing_lifetime_args.stderr +++ b/tests/ui/generic-associated-types/missing_lifetime_args.stderr @@ -48,17 +48,18 @@ help: add missing lifetime arguments LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y<'_, '_> = (&'c u32, &'d u32)>>) {} | ++++++++ -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/missing_lifetime_args.rs:11:26 | LL | fn foo<'c, 'd>(_arg: Box<dyn X<Y = (&'c u32, &'d u32)>>) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/missing_lifetime_args.rs:2:10 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'a, 'b>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs index d6fc3df1026..c828691bb30 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs +++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.rs @@ -10,7 +10,7 @@ const _: () = { //~| ERROR associated type takes 0 generic arguments but 1 generic argument //~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments //~| ERROR associated type takes 0 generic arguments but 1 generic argument - //~| ERROR the trait `X` cannot be made into an object + //~| ERROR the trait `X` is not dyn compatible }; fn main() {} diff --git a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr index 91f0f7b3fcf..5c9e9dbe3d7 100644 --- a/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr +++ b/tests/ui/generic-associated-types/parse/trait-path-type-error-once-implemented.stderr @@ -92,17 +92,18 @@ LL | type Y<'a>; | ^ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/trait-path-type-error-once-implemented.rs:6:23 | LL | fn f2<'a>(arg : Box<dyn X<Y<1> = &'a ()>>) {} - | ^^^^^^^^^^^^^^^^^^^^ `X` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/trait-path-type-error-once-implemented.rs:2:10 | LL | trait X { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | type Y<'a>; | ^ ...because it contains the generic associated type `Y` = help: consider moving `Y` to another trait diff --git a/tests/ui/generic-associated-types/trait-objects.base.stderr b/tests/ui/generic-associated-types/trait-objects.base.stderr index 0b5a9b9f7fb..fe9ab165d4a 100644 --- a/tests/ui/generic-associated-types/trait-objects.base.stderr +++ b/tests/ui/generic-associated-types/trait-objects.base.stderr @@ -1,44 +1,47 @@ -error[E0038]: the trait `StreamingIterator` cannot be made into an object +error[E0038]: the trait `StreamingIterator` is not dyn compatible --> $DIR/trait-objects.rs:13:21 | LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/trait-objects.rs:7:10 | LL | trait StreamingIterator { - | ----------------- this trait cannot be made into an object... + | ----------------- this trait is not dyn compatible... LL | type Item<'a> where Self: 'a; | ^^^^ ...because it contains the generic associated type `Item` = help: consider moving `Item` to another trait -error[E0038]: the trait `StreamingIterator` cannot be made into an object +error[E0038]: the trait `StreamingIterator` is not dyn compatible --> $DIR/trait-objects.rs:15:7 | LL | x.size_hint().0 - | ^^^^^^^^^ `StreamingIterator` cannot be made into an object + | ^^^^^^^^^ `StreamingIterator` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/trait-objects.rs:7:10 | LL | trait StreamingIterator { - | ----------------- this trait cannot be made into an object... + | ----------------- this trait is not dyn compatible... LL | type Item<'a> where Self: 'a; | ^^^^ ...because it contains the generic associated type `Item` = help: consider moving `Item` to another trait -error[E0038]: the trait `StreamingIterator` cannot be made into an object +error[E0038]: the trait `StreamingIterator` is not dyn compatible --> $DIR/trait-objects.rs:15:5 | LL | x.size_hint().0 - | ^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object + | ^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/trait-objects.rs:7:10 | LL | trait StreamingIterator { - | ----------------- this trait cannot be made into an object... + | ----------------- this trait is not dyn compatible... LL | type Item<'a> where Self: 'a; | ^^^^ ...because it contains the generic associated type `Item` = help: consider moving `Item` to another trait diff --git a/tests/ui/generic-associated-types/trait-objects.rs b/tests/ui/generic-associated-types/trait-objects.rs index bad9289ee5e..ed324b562e1 100644 --- a/tests/ui/generic-associated-types/trait-objects.rs +++ b/tests/ui/generic-associated-types/trait-objects.rs @@ -6,10 +6,10 @@ trait StreamingIterator { } fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize { - //~^ the trait `StreamingIterator` cannot be made into an object + //~^ the trait `StreamingIterator` is not dyn compatible x.size_hint().0 - //~^ the trait `StreamingIterator` cannot be made into an object - //~| the trait `StreamingIterator` cannot be made into an object + //~^ the trait `StreamingIterator` is not dyn compatible + //~| the trait `StreamingIterator` is not dyn compatible } fn main() {} diff --git a/tests/ui/generic-associated-types/trait-objects.stderr b/tests/ui/generic-associated-types/trait-objects.stderr index 3e74776f999..56a1cb1906f 100644 --- a/tests/ui/generic-associated-types/trait-objects.stderr +++ b/tests/ui/generic-associated-types/trait-objects.stderr @@ -1,44 +1,47 @@ -error[E0038]: the trait `StreamingIterator` cannot be made into an object +error[E0038]: the trait `StreamingIterator` is not dyn compatible --> $DIR/trait-objects.rs:8:21 | LL | fn min_size(x: &mut dyn for<'a> StreamingIterator<Item<'a> = &'a i32>) -> usize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/trait-objects.rs:2:10 | LL | trait StreamingIterator { - | ----------------- this trait cannot be made into an object... + | ----------------- this trait is not dyn compatible... LL | type Item<'a> where Self: 'a; | ^^^^ ...because it contains the generic associated type `Item` = help: consider moving `Item` to another trait -error[E0038]: the trait `StreamingIterator` cannot be made into an object +error[E0038]: the trait `StreamingIterator` is not dyn compatible --> $DIR/trait-objects.rs:10:7 | LL | x.size_hint().0 - | ^^^^^^^^^ `StreamingIterator` cannot be made into an object + | ^^^^^^^^^ `StreamingIterator` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/trait-objects.rs:2:10 | LL | trait StreamingIterator { - | ----------------- this trait cannot be made into an object... + | ----------------- this trait is not dyn compatible... LL | type Item<'a> where Self: 'a; | ^^^^ ...because it contains the generic associated type `Item` = help: consider moving `Item` to another trait -error[E0038]: the trait `StreamingIterator` cannot be made into an object +error[E0038]: the trait `StreamingIterator` is not dyn compatible --> $DIR/trait-objects.rs:10:5 | LL | x.size_hint().0 - | ^^^^^^^^^^^^^ `StreamingIterator` cannot be made into an object + | ^^^^^^^^^^^^^ `StreamingIterator` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/trait-objects.rs:2:10 | LL | trait StreamingIterator { - | ----------------- this trait cannot be made into an object... + | ----------------- this trait is not dyn compatible... LL | type Item<'a> where Self: 'a; | ^^^^ ...because it contains the generic associated type `Item` = help: consider moving `Item` to another trait diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs index aeace9f2158..5d039cd5dc6 100644 --- a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs +++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.rs @@ -12,8 +12,8 @@ fn needs_bar(_: *mut Type2) {} fn main() { let x: &dyn Foo = &(); - //~^ ERROR the trait `Foo` cannot be made into an object - //~| ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible + //~| ERROR the trait `Foo` is not dyn compatible needs_bar(x); //~^ ERROR mismatched types diff --git a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr index d48bf8a471d..fc3d9c2171d 100644 --- a/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr +++ b/tests/ui/higher-ranked/trait-bounds/span-bug-issue-121597.stderr @@ -1,31 +1,33 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/span-bug-issue-121597.rs:14:23 | LL | let x: &dyn Foo = &(); - | ^^^ `Foo` cannot be made into an object + | ^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/span-bug-issue-121597.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... = note: required for the cast from `&()` to `&dyn Foo` -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/span-bug-issue-121597.rs:14:12 | LL | let x: &dyn Foo = &(); - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/span-bug-issue-121597.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... error[E0308]: mismatched types --> $DIR/span-bug-issue-121597.rs:18:15 diff --git a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs index 76dbb05f53d..046ced072ba 100644 --- a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.rs @@ -19,7 +19,7 @@ impl DynIncompatible for B { } } -fn car() -> dyn DynIncompatible { //~ ERROR the trait `DynIncompatible` cannot be made into an object +fn car() -> dyn DynIncompatible { //~ ERROR the trait `DynIncompatible` is not dyn compatible //~^ ERROR return type cannot have an unboxed trait object if true { return A; @@ -27,11 +27,11 @@ fn car() -> dyn DynIncompatible { //~ ERROR the trait `DynIncompatible` cannot b B } -fn cat() -> Box<dyn DynIncompatible> { //~ ERROR the trait `DynIncompatible` cannot be made into an +fn cat() -> Box<dyn DynIncompatible> { //~ ERROR the trait `DynIncompatible` is not dyn compatible if true { - return Box::new(A); //~ ERROR cannot be made into an object + return Box::new(A); //~ ERROR is not dyn compatible } - Box::new(B) //~ ERROR cannot be made into an object + Box::new(B) //~ ERROR is not dyn compatible } fn main() {} diff --git a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr index 576bd909cbc..4abd7bcf31c 100644 --- a/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr +++ b/tests/ui/impl-trait/dyn-incompatible-trait-in-return-position-dyn-trait.stderr @@ -1,19 +1,22 @@ -error[E0038]: the trait `DynIncompatible` cannot be made into an object +error[E0038]: the trait `DynIncompatible` is not dyn compatible --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:22:13 | LL | fn car() -> dyn DynIncompatible { - | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | LL | trait DynIncompatible { - | --------------- this trait cannot be made into an object... + | --------------- this trait is not dyn compatible... LL | fn foo() -> Self; | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead: + = help: the following types implement `DynIncompatible`: A B + consider defining an enum where each variant holds one of these types, + implementing `DynIncompatible` for this new enum and using it instead help: consider turning `foo` into a method by giving it a `&self` argument | LL | fn foo(&self) -> Self; @@ -23,22 +26,25 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() -> Self where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `DynIncompatible` cannot be made into an object +error[E0038]: the trait `DynIncompatible` is not dyn compatible --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:30:17 | LL | fn cat() -> Box<dyn DynIncompatible> { - | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | LL | trait DynIncompatible { - | --------------- this trait cannot be made into an object... + | --------------- this trait is not dyn compatible... LL | fn foo() -> Self; | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead: + = help: the following types implement `DynIncompatible`: A B + consider defining an enum where each variant holds one of these types, + implementing `DynIncompatible` for this new enum and using it instead help: consider turning `foo` into a method by giving it a `&self` argument | LL | fn foo(&self) -> Self; @@ -65,22 +71,25 @@ LL | } LL ~ Box::new(B) | -error[E0038]: the trait `DynIncompatible` cannot be made into an object +error[E0038]: the trait `DynIncompatible` is not dyn compatible --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:32:16 | LL | return Box::new(A); - | ^^^^^^^^^^^ `DynIncompatible` cannot be made into an object + | ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | LL | trait DynIncompatible { - | --------------- this trait cannot be made into an object... + | --------------- this trait is not dyn compatible... LL | fn foo() -> Self; | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead: + = help: the following types implement `DynIncompatible`: A B + consider defining an enum where each variant holds one of these types, + implementing `DynIncompatible` for this new enum and using it instead = note: required for the cast from `Box<A>` to `Box<(dyn DynIncompatible + 'static)>` help: consider turning `foo` into a method by giving it a `&self` argument | @@ -91,22 +100,25 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() -> Self where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `DynIncompatible` cannot be made into an object +error[E0038]: the trait `DynIncompatible` is not dyn compatible --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:34:5 | LL | Box::new(B) - | ^^^^^^^^^^^ `DynIncompatible` cannot be made into an object + | ^^^^^^^^^^^ `DynIncompatible` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-in-return-position-dyn-trait.rs:4:8 | LL | trait DynIncompatible { - | --------------- this trait cannot be made into an object... + | --------------- this trait is not dyn compatible... LL | fn foo() -> Self; | ^^^ ...because associated function `foo` has no `self` parameter - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `DynIncompatible` for this new enum and using it instead: + = help: the following types implement `DynIncompatible`: A B + consider defining an enum where each variant holds one of these types, + implementing `DynIncompatible` for this new enum and using it instead = note: required for the cast from `Box<B>` to `Box<(dyn DynIncompatible + 'static)>` help: consider turning `foo` into a method by giving it a `&self` argument | diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr index 28a0f7461e2..146a3d21068 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.stderr +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.current.stderr @@ -1,11 +1,11 @@ error[E0407]: method `line_stream` is not a member of trait `X` - --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:5 + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5 | LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X` error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter - --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:22:21 + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21 | LL | type LineStream<'a, Repr> | -- ---- @@ -18,7 +18,7 @@ LL | type LineStream<'c, 'd> = impl Stream; | found 0 type parameters error[E0277]: `()` is not a future - --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:43 + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:43 | LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr new file mode 100644 index 00000000000..3c24eb9adbe --- /dev/null +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.next.stderr @@ -0,0 +1,29 @@ +error[E0407]: method `line_stream` is not a member of trait `X` + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:5 + | +LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not a member of trait `X` + +error[E0049]: type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:25:21 + | +LL | type LineStream<'a, Repr> + | -- ---- + | | + | expected 1 type parameter +... +LL | type LineStream<'c, 'd> = impl Stream; + | ^^ ^^ + | | + | found 0 type parameters + +error[E0271]: type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` + --> $DIR/ice-unexpected-param-type-whensubstituting-in-region-112823.rs:28:43 + | +LL | fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0049, E0271, E0407. +For more information about an error, try `rustc --explain E0049`. diff --git a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs index d6fa56663a3..c97bd179943 100644 --- a/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs +++ b/tests/ui/impl-trait/ice-unexpected-param-type-whensubstituting-in-region-112823.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver // test for ICE #112823 // Unexpected parameter Type(Repr) when substituting in region @@ -23,8 +26,9 @@ impl X for Y { //~^ ERROR type `LineStream` has 0 type parameters but its trait declaration has 1 type parameter type LineStreamFut<'a, Repr> = impl Future<Output = Self::LineStream<'a, Repr>>; fn line_stream<'a, Repr>(&'a self) -> Self::LineStreamFut<'a, Repr> {} - //~^ ERROR `()` is not a future - //~^^ method `line_stream` is not a member of trait `X` + //[current]~^ ERROR `()` is not a future + //[next]~^^ ERROR type mismatch resolving `<Y as X>::LineStreamFut<'a, Repr> == ()` + //~^^^ method `line_stream` is not a member of trait `X` } pub fn main() {} diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs index daf29a0005d..d6fa34419d2 100644 --- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.rs @@ -14,13 +14,13 @@ impl MyTrait for Outer { } impl dyn MyTrait { - //~^ ERROR the trait `MyTrait` cannot be made into an object + //~^ ERROR the trait `MyTrait` is not dyn compatible fn other(&self) -> impl Marker { - //~^ ERROR the trait `MyTrait` cannot be made into an object + //~^ ERROR the trait `MyTrait` is not dyn compatible MyTrait::foo(&self) //~^ ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied //~| ERROR the trait bound `&dyn MyTrait: MyTrait` is not satisfied - //~| ERROR the trait `MyTrait` cannot be made into an object + //~| ERROR the trait `MyTrait` is not dyn compatible } } diff --git a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr index a975b6204aa..44ca09150fe 100644 --- a/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr +++ b/tests/ui/impl-trait/in-trait/cycle-effective-visibilities-during-dyn-compatibility-check.stderr @@ -8,21 +8,22 @@ LL | MyTrait::foo(&self) | = help: the trait `MyTrait` is implemented for `Outer` -error[E0038]: the trait `MyTrait` cannot be made into an object +error[E0038]: the trait `MyTrait` is not dyn compatible --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:20:9 | LL | MyTrait::foo(&self) - | ^^^^^^^^^^^^ `MyTrait` cannot be made into an object + | ^^^^^^^^^^^^ `MyTrait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22 | LL | trait MyTrait { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | fn foo(&self) -> impl Marker; | ^^^^^^^^^^^ ...because method `foo` references an `impl Trait` type in its return type = help: consider moving `foo` to another trait - = help: only type `Outer` implements the trait, consider using it directly instead + = help: only type `Outer` implements `MyTrait`; consider using it directly instead. error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:20:9 @@ -32,37 +33,39 @@ LL | MyTrait::foo(&self) | = help: the trait `MyTrait` is implemented for `Outer` -error[E0038]: the trait `MyTrait` cannot be made into an object +error[E0038]: the trait `MyTrait` is not dyn compatible --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:16:6 | LL | impl dyn MyTrait { - | ^^^^^^^^^^^ `MyTrait` cannot be made into an object + | ^^^^^^^^^^^ `MyTrait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22 | LL | trait MyTrait { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | fn foo(&self) -> impl Marker; | ^^^^^^^^^^^ ...because method `foo` references an `impl Trait` type in its return type = help: consider moving `foo` to another trait - = help: only type `Outer` implements the trait, consider using it directly instead + = help: only type `Outer` implements `MyTrait`; consider using it directly instead. -error[E0038]: the trait `MyTrait` cannot be made into an object +error[E0038]: the trait `MyTrait` is not dyn compatible --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:18:15 | LL | fn other(&self) -> impl Marker { - | ^^^^ `MyTrait` cannot be made into an object + | ^^^^ `MyTrait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/cycle-effective-visibilities-during-dyn-compatibility-check.rs:5:22 | LL | trait MyTrait { - | ------- this trait cannot be made into an object... + | ------- this trait is not dyn compatible... LL | fn foo(&self) -> impl Marker; | ^^^^^^^^^^^ ...because method `foo` references an `impl Trait` type in its return type = help: consider moving `foo` to another trait - = help: only type `Outer` implements the trait, consider using it directly instead + = help: only type `Outer` implements `MyTrait`; consider using it directly instead. error: aborting due to 5 previous errors diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs index 5cca4ad839c..85b1ba269fc 100644 --- a/tests/ui/impl-trait/in-trait/dyn-compatibility.rs +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.rs @@ -12,9 +12,9 @@ impl Foo for u32 { fn main() { let i = Box::new(42_u32) as Box<dyn Foo>; - //~^ ERROR the trait `Foo` cannot be made into an object - //~| ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible + //~| ERROR the trait `Foo` is not dyn compatible let s = i.baz(); - //~^ ERROR the trait `Foo` cannot be made into an object - //~| ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible + //~| ERROR the trait `Foo` is not dyn compatible } diff --git a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr index 115cb014b8c..87a5480b1e3 100644 --- a/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr +++ b/tests/ui/impl-trait/in-trait/dyn-compatibility.stderr @@ -1,66 +1,70 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility.rs:14:33 | LL | let i = Box::new(42_u32) as Box<dyn Foo>; - | ^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn baz(&self) -> impl Debug; | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type = help: consider moving `baz` to another trait - = help: only type `u32` implements the trait, consider using it directly instead + = help: only type `u32` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility.rs:17:15 | LL | let s = i.baz(); - | ^^^ `Foo` cannot be made into an object + | ^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn baz(&self) -> impl Debug; | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type = help: consider moving `baz` to another trait - = help: only type `u32` implements the trait, consider using it directly instead + = help: only type `u32` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility.rs:17:13 | LL | let s = i.baz(); - | ^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn baz(&self) -> impl Debug; | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type = help: consider moving `baz` to another trait - = help: only type `u32` implements the trait, consider using it directly instead + = help: only type `u32` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/dyn-compatibility.rs:14:13 | LL | let i = Box::new(42_u32) as Box<dyn Foo>; - | ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-compatibility.rs:4:22 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn baz(&self) -> impl Debug; | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type = help: consider moving `baz` to another trait - = help: only type `u32` implements the trait, consider using it directly instead + = help: only type `u32` implements `Foo`; consider using it directly instead. = note: required for the cast from `Box<u32>` to `Box<dyn Foo>` error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs b/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs index 600dba03b74..5b891170a4f 100644 --- a/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs +++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.rs @@ -4,5 +4,5 @@ extern crate rpitit; fn main() { let _: &dyn rpitit::Foo = todo!(); - //~^ ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible } diff --git a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr index 895d8686742..07d09468b04 100644 --- a/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr +++ b/tests/ui/impl-trait/in-trait/foreign-dyn-error.stderr @@ -1,15 +1,16 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/foreign-dyn-error.rs:6:12 | LL | let _: &dyn rpitit::Foo = todo!(); - | ^^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/auxiliary/rpitit.rs:4:21 | LL | fn bar(self) -> impl Deref<Target = impl Sized>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait cannot be made into an object because method `bar` references an `impl Trait` type in its return type - = help: only type `rpitit::Foreign` implements the trait, consider using it directly instead + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait is not dyn compatible because method `bar` references an `impl Trait` type in its return type + = help: only type `rpitit::Foreign` implements `Foo`; consider using it directly instead. error: aborting due to 1 previous error diff --git a/tests/ui/impl-trait/issue-102605.stderr b/tests/ui/impl-trait/issue-102605.stderr index dcb22797173..ed6663fa61f 100644 --- a/tests/ui/impl-trait/issue-102605.stderr +++ b/tests/ui/impl-trait/issue-102605.stderr @@ -14,20 +14,11 @@ LL | convert_result(foo()) | | | arguments to this function are incorrect | -note: calling an async function returns a future - --> $DIR/issue-102605.rs:13:20 - | -LL | convert_result(foo()) - | ^^^^^ note: function defined here --> $DIR/issue-102605.rs:7:4 | LL | fn convert_result<T, E>(r: Result<T, E>) -> Option<T> { | ^^^^^^^^^^^^^^ --------------- -help: consider `await`ing on the `Future` - | -LL | convert_result(foo().await) - | ++++++ help: try wrapping the expression in `Err` | LL | convert_result(Err(foo())) diff --git a/tests/ui/inference/issue-72616.stderr b/tests/ui/inference/issue-72616.stderr index 02c92c1c11d..a26f9a1ff56 100644 --- a/tests/ui/inference/issue-72616.stderr +++ b/tests/ui/inference/issue-72616.stderr @@ -6,11 +6,14 @@ LL | if String::from("a") == "a".try_into().unwrap() {} | | | type must be known at this point | - = note: multiple `impl`s satisfying `String: PartialEq<_>` found in the `alloc` crate: - - impl PartialEq for String; - - impl<'a, 'b> PartialEq<&'a str> for String; - - impl<'a, 'b> PartialEq<Cow<'a, str>> for String; - - impl<'a, 'b> PartialEq<str> for String; + = note: cannot satisfy `String: PartialEq<_>` + = help: the following types implement trait `PartialEq<Rhs>`: + `String` implements `PartialEq<&str>` + `String` implements `PartialEq<ByteStr>` + `String` implements `PartialEq<ByteString>` + `String` implements `PartialEq<Cow<'_, str>>` + `String` implements `PartialEq<str>` + `String` implements `PartialEq` help: try using a fully qualified path to specify the expected types | LL | if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {} diff --git a/tests/ui/inference/issue-72690.stderr b/tests/ui/inference/issue-72690.stderr index 6391672f861..2d09f667ae2 100644 --- a/tests/ui/inference/issue-72690.stderr +++ b/tests/ui/inference/issue-72690.stderr @@ -15,6 +15,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -41,6 +42,7 @@ LL | |x| String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -57,6 +59,7 @@ LL | let _ = "x".as_ref(); | ^ ------ type must be known at this point | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -83,6 +86,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -109,6 +113,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -135,6 +140,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -161,6 +167,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -187,6 +194,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; @@ -213,6 +221,7 @@ LL | String::from("x".as_ref()); | ^^^^^^ | = note: multiple `impl`s satisfying `str: AsRef<_>` found in the following crates: `core`, `std`: + - impl AsRef<ByteStr> for str; - impl AsRef<OsStr> for str; - impl AsRef<Path> for str; - impl AsRef<[u8]> for str; diff --git a/tests/ui/issues/issue-18959.stderr b/tests/ui/issues/issue-18959.stderr index 5bb452250aa..49d501c397f 100644 --- a/tests/ui/issues/issue-18959.stderr +++ b/tests/ui/issues/issue-18959.stderr @@ -1,77 +1,82 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/issue-18959.rs:11:12 | LL | fn foo(b: &dyn Bar) { - | ^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } | ^^^ ...because method `foo` has generic type parameters LL | pub trait Bar: Foo { } - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/issue-18959.rs:13:5 | LL | b.foo(&0) - | ^^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } | ^^^ ...because method `foo` has generic type parameters LL | pub trait Bar: Foo { } - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/issue-18959.rs:19:15 | LL | let test: &dyn Bar = &mut thing; - | ^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } | ^^^ ...because method `foo` has generic type parameters LL | pub trait Bar: Foo { } - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/issue-18959.rs:19:26 | LL | let test: &dyn Bar = &mut thing; - | ^^^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } | ^^^ ...because method `foo` has generic type parameters LL | pub trait Bar: Foo { } - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait = note: required for the cast from `&mut Thing` to `&dyn Bar` -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/issue-18959.rs:22:9 | LL | foo(test); - | ^^^^ `Bar` cannot be made into an object + | ^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-18959.rs:1:20 | LL | pub trait Foo { fn foo<T>(&self, ext_thing: &T); } | ^^^ ...because method `foo` has generic type parameters LL | pub trait Bar: Foo { } - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... = help: consider moving `foo` to another trait error: aborting due to 5 previous errors diff --git a/tests/ui/issues/issue-19380.stderr b/tests/ui/issues/issue-19380.stderr index afbe67befa1..7d4812c3693 100644 --- a/tests/ui/issues/issue-19380.stderr +++ b/tests/ui/issues/issue-19380.stderr @@ -1,17 +1,18 @@ -error[E0038]: the trait `Qiz` cannot be made into an object +error[E0038]: the trait `Qiz` is not dyn compatible --> $DIR/issue-19380.rs:11:29 | LL | foos: &'static [&'static (dyn Qiz + 'static)] - | ^^^^^^^^^^^^^^^^^ `Qiz` cannot be made into an object + | ^^^^^^^^^^^^^^^^^ `Qiz` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-19380.rs:2:6 | LL | trait Qiz { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn qiz(); | ^^^ ...because associated function `qiz` has no `self` parameter - = help: only type `Foo` implements the trait, consider using it directly instead + = help: only type `Foo` implements `Qiz`; consider using it directly instead. help: consider turning `qiz` into a method by giving it a `&self` argument | LL | fn qiz(&self); @@ -21,20 +22,21 @@ help: alternatively, consider constraining `qiz` so it does not apply to trait o LL | fn qiz() where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Qiz` cannot be made into an object +error[E0038]: the trait `Qiz` is not dyn compatible --> $DIR/issue-19380.rs:16:33 | LL | const BAR : Bar = Bar { foos: &[&FOO]}; - | ^^^^ `Qiz` cannot be made into an object + | ^^^^ `Qiz` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-19380.rs:2:6 | LL | trait Qiz { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn qiz(); | ^^^ ...because associated function `qiz` has no `self` parameter - = help: only type `Foo` implements the trait, consider using it directly instead + = help: only type `Foo` implements `Qiz`; consider using it directly instead. = note: required for the cast from `&Foo` to `&'static (dyn Qiz + 'static)` help: consider turning `qiz` into a method by giving it a `&self` argument | @@ -45,20 +47,21 @@ help: alternatively, consider constraining `qiz` so it does not apply to trait o LL | fn qiz() where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Qiz` cannot be made into an object +error[E0038]: the trait `Qiz` is not dyn compatible --> $DIR/issue-19380.rs:16:31 | LL | const BAR : Bar = Bar { foos: &[&FOO]}; - | ^^^^^^^ `Qiz` cannot be made into an object + | ^^^^^^^ `Qiz` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-19380.rs:2:6 | LL | trait Qiz { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn qiz(); | ^^^ ...because associated function `qiz` has no `self` parameter - = help: only type `Foo` implements the trait, consider using it directly instead + = help: only type `Foo` implements `Qiz`; consider using it directly instead. help: consider turning `qiz` into a method by giving it a `&self` argument | LL | fn qiz(&self); diff --git a/tests/ui/issues/issue-26056.stderr b/tests/ui/issues/issue-26056.stderr index be5453ec19d..d1cdf43351e 100644 --- a/tests/ui/issues/issue-26056.stderr +++ b/tests/ui/issues/issue-26056.stderr @@ -1,16 +1,17 @@ -error[E0038]: the trait `Map` cannot be made into an object - --> $DIR/issue-26056.rs:20:13 +error[E0038]: the trait `Map` is not dyn compatible + --> $DIR/issue-26056.rs:20:17 | LL | as &dyn Map<Key=u32,MapValue=u32>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Map` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `Map` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-26056.rs:9:12 | LL | trait Map: MapLookup<<Self as Map>::Key> { | --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-33941.stderr b/tests/ui/issues/issue-33941.current.stderr index 9535ea57430..d653bbd3274 100644 --- a/tests/ui/issues/issue-33941.stderr +++ b/tests/ui/issues/issue-33941.current.stderr @@ -1,5 +1,5 @@ error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` - --> $DIR/issue-33941.rs:6:36 + --> $DIR/issue-33941.rs:9:36 | LL | for _ in HashMap::new().iter().cloned() {} | ^^^^^^ expected `&_`, found `(&_, &_)` @@ -7,7 +7,7 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: expected reference `&_` found tuple `(&_, &_)` note: the method call chain might not have had the expected associated types - --> $DIR/issue-33941.rs:6:29 + --> $DIR/issue-33941.rs:9:29 | LL | for _ in HashMap::new().iter().cloned() {} | -------------- ^^^^^^ `Iterator::Item` is `(&_, &_)` here @@ -17,7 +17,7 @@ note: required by a bound in `cloned` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` - --> $DIR/issue-33941.rs:6:14 + --> $DIR/issue-33941.rs:9:14 | LL | for _ in HashMap::new().iter().cloned() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `(&_, &_)` diff --git a/tests/ui/issues/issue-33941.next.stderr b/tests/ui/issues/issue-33941.next.stderr new file mode 100644 index 00000000000..a5a6e51545a --- /dev/null +++ b/tests/ui/issues/issue-33941.next.stderr @@ -0,0 +1,25 @@ +error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + --> $DIR/issue-33941.rs:9:36 + | +LL | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^ expected `&_`, found `(&_, &_)` + | + = note: expected reference `&_` + found tuple `(&_, &_)` +note: required by a bound in `cloned` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error[E0271]: expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + --> $DIR/issue-33941.rs:9:14 + | +LL | for _ in HashMap::new().iter().cloned() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `(&_, &_)` + | + = note: expected reference `&_` + found tuple `(&_, &_)` + = note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `Iterator` + = note: required for `Cloned<std::collections::hash_map::Iter<'_, _, _>>` to implement `IntoIterator` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/issues/issue-33941.rs b/tests/ui/issues/issue-33941.rs index 7b5be30834b..b0736204a08 100644 --- a/tests/ui/issues/issue-33941.rs +++ b/tests/ui/issues/issue-33941.rs @@ -1,8 +1,12 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver //@ compile-flags: -Zdeduplicate-diagnostics=yes use std::collections::HashMap; fn main() { - for _ in HashMap::new().iter().cloned() {} //~ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + for _ in HashMap::new().iter().cloned() {} //~^ ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` + //~| ERROR expected `Iter<'_, _, _>` to be an iterator that yields `&_`, but it yields `(&_, &_)` } diff --git a/tests/ui/issues/issue-50714-1.rs b/tests/ui/issues/issue-50714-1.rs deleted file mode 100644 index a25940ce1cb..00000000000 --- a/tests/ui/issues/issue-50714-1.rs +++ /dev/null @@ -1,11 +0,0 @@ -// Regression test for issue 50714, make sure that this isn't a linker error. - -#![no_std] -#![feature(start)] - -extern crate std; - -#[start] -fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq { //~ ERROR [E0647] - 0 -} diff --git a/tests/ui/issues/issue-50714-1.stderr b/tests/ui/issues/issue-50714-1.stderr deleted file mode 100644 index 7593ac38346..00000000000 --- a/tests/ui/issues/issue-50714-1.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0647]: `#[start]` function is not allowed to have a `where` clause - --> $DIR/issue-50714-1.rs:9:50 - | -LL | fn start(_: isize, _: *const *const u8) -> isize where fn(&()): Eq { - | ^^^^^^^^^^^^^^^^^ `#[start]` function cannot have a `where` clause - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0647`. diff --git a/tests/ui/issues/issue-50781.rs b/tests/ui/issues/issue-50781.rs index 32253c3c236..ab90db1cadc 100644 --- a/tests/ui/issues/issue-50781.rs +++ b/tests/ui/issues/issue-50781.rs @@ -9,11 +9,11 @@ impl X for () { } impl Trait for dyn X {} -//~^ ERROR the trait `X` cannot be made into an object +//~^ ERROR the trait `X` is not dyn compatible 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 + //~^ ERROR the trait `X` is not dyn compatible + //~| ERROR the trait `X` is not dyn compatible } diff --git a/tests/ui/issues/issue-50781.stderr b/tests/ui/issues/issue-50781.stderr index 3e54a53aa95..293e9839944 100644 --- a/tests/ui/issues/issue-50781.stderr +++ b/tests/ui/issues/issue-50781.stderr @@ -1,51 +1,54 @@ -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/issue-50781.rs:11:16 | LL | impl Trait for dyn X {} - | ^^^^^ `X` cannot be made into an object + | ^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + 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... + | - this trait is not dyn compatible... 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 + = help: only type `()` implements `X`; consider using it directly instead. -error[E0038]: the trait `X` cannot be made into an object +error[E0038]: the trait `X` is not dyn compatible --> $DIR/issue-50781.rs:16:23 | LL | <dyn X as X>::foo(&()); - | ^^^ `X` cannot be made into an object + | ^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + 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... + | - this trait is not dyn compatible... 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 + = help: only type `()` implements `X`; 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 +error[E0038]: the trait `X` is not dyn compatible --> $DIR/issue-50781.rs:16:6 | LL | <dyn X as X>::foo(&()); - | ^^^^^ `X` cannot be made into an object + | ^^^^^ `X` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + 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... + | - this trait is not dyn compatible... 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 + = help: only type `()` implements `X`; consider using it directly instead. error: aborting due to 3 previous errors diff --git a/tests/ui/issues/issue-9575.rs b/tests/ui/issues/issue-9575.rs deleted file mode 100644 index 06b252990b6..00000000000 --- a/tests/ui/issues/issue-9575.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(start)] - -#[start] -fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize { - //~^ `#[start]` function has wrong type - 0 -} diff --git a/tests/ui/issues/issue-9575.stderr b/tests/ui/issues/issue-9575.stderr deleted file mode 100644 index 2f6e2687d24..00000000000 --- a/tests/ui/issues/issue-9575.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0308]: `#[start]` function has wrong type - --> $DIR/issue-9575.rs:4:1 - | -LL | fn start(argc: isize, argv: *const *const u8, crate_map: *const u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters - | - = note: expected signature `fn(isize, *const *const u8) -> _` - found signature `fn(isize, *const *const u8, *const u8) -> _` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr index c392879db3e..83446fc9ec0 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -19,33 +19,35 @@ note: required by a bound in `take_param` LL | fn take_param<T:Foo>(foo: &T) { } | ^^^ required by this bound in `take_param` -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/kindck-inherited-copy-bound.rs:28:19 | LL | let z = &x as &dyn Foo; - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/kindck-inherited-copy-bound.rs:10:13 | LL | trait Foo : Copy { | --- ^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/kindck-inherited-copy-bound.rs:28:13 | LL | let z = &x as &dyn Foo; - | ^^ `Foo` cannot be made into an object + | ^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/kindck-inherited-copy-bound.rs:10:13 | LL | trait Foo : Copy { | --- ^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... = note: required for the cast from `&Box<{integer}>` to `&dyn Foo` error: aborting due to 3 previous errors diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr index 34dcad13af3..271e5afb9e7 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.dyn_compatible_for_dispatch.stderr @@ -19,19 +19,20 @@ note: required by a bound in `take_param` LL | fn take_param<T:Foo>(foo: &T) { } | ^^^ required by this bound in `take_param` -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/kindck-inherited-copy-bound.rs:28:13 | LL | let z = &x as &dyn Foo; - | ^^ `Foo` cannot be made into an object + | ^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/kindck-inherited-copy-bound.rs:10:13 | LL | trait Foo : Copy { | --- ^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... = note: required for the cast from `&Box<i32>` to `&dyn Foo` error: aborting due to 2 previous errors diff --git a/tests/ui/lang-items/issue-19660.rs b/tests/ui/lang-items/issue-19660.rs deleted file mode 100644 index aff57df7ece..00000000000 --- a/tests/ui/lang-items/issue-19660.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ error-pattern: requires `copy` lang_item - -#![feature(lang_items, start, no_core)] -#![no_core] - -#[lang = "sized"] -trait Sized { } - -struct S; - -#[start] -fn main(_: isize, _: *const *const u8) -> isize { - let _ = S; - 0 -} diff --git a/tests/ui/lang-items/issue-19660.stderr b/tests/ui/lang-items/issue-19660.stderr deleted file mode 100644 index e5a8a143d03..00000000000 --- a/tests/ui/lang-items/issue-19660.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: requires `copy` lang_item - -error: aborting due to 1 previous error - diff --git a/tests/ui/lang-items/lang-item-missing.rs b/tests/ui/lang-items/lang-item-missing.rs index 8762594202a..5b832a5bb8f 100644 --- a/tests/ui/lang-items/lang-item-missing.rs +++ b/tests/ui/lang-items/lang-item-missing.rs @@ -3,10 +3,11 @@ //@ error-pattern: requires `sized` lang_item -#![feature(start, no_core)] +#![feature(lang_items, no_core)] #![no_core] +#![no_main] -#[start] -fn start(argc: isize, argv: *const *const u8) -> isize { - 0 +#[no_mangle] +extern "C" fn main(_argc: i32, _argv: *const *const u8) -> i32 { + loop {} } diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs new file mode 100644 index 00000000000..9b634ee8ee3 --- /dev/null +++ b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.rs @@ -0,0 +1,15 @@ +//@ error-pattern: requires `copy` lang_item + +#![feature(lang_items, no_core)] +#![no_core] +#![no_main] + +#[lang = "sized"] +trait Sized { } + +struct S; + +#[no_mangle] +extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 { + argc +} diff --git a/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr new file mode 100644 index 00000000000..3dc7716ecd2 --- /dev/null +++ b/tests/ui/lang-items/missing-copy-lang-item-issue-19660.stderr @@ -0,0 +1,8 @@ +error: requires `copy` lang_item + --> $DIR/missing-copy-lang-item-issue-19660.rs:14:5 + | +LL | argc + | ^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/layout/reprc-power-alignment.rs b/tests/ui/layout/reprc-power-alignment.rs new file mode 100644 index 00000000000..f6c1df55988 --- /dev/null +++ b/tests/ui/layout/reprc-power-alignment.rs @@ -0,0 +1,152 @@ +//@ check-pass +//@ compile-flags: --target powerpc64-ibm-aix +//@ needs-llvm-components: powerpc +//@ add-core-stubs +#![feature(no_core)] +#![no_core] +#![no_std] + +extern crate minicore; +use minicore::*; + +#[warn(uses_power_alignment)] + +#[repr(C)] +pub struct Floats { + a: f64, + b: u8, + c: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + d: f32, +} + +pub struct Floats2 { + a: f64, + b: u32, + c: f64, +} + +#[repr(C)] +pub struct Floats3 { + a: f32, + b: f32, + c: i64, +} + +#[repr(C)] +pub struct Floats4 { + a: u64, + b: u32, + c: f32, +} + +#[repr(C)] +pub struct Floats5 { + a: f32, + b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + c: f32, +} + +#[repr(C)] +pub struct FloatAgg1 { + x: Floats, + y: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} + +#[repr(C)] +pub struct FloatAgg2 { + x: i64, + y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} + +#[repr(C)] +pub struct FloatAgg3 { + x: FloatAgg1, + // NOTE: the "power" alignment rule is infectious to nested struct fields. + y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + z: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} + +#[repr(C)] +pub struct FloatAgg4 { + x: FloatAgg1, + y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} + +#[repr(C)] +pub struct FloatAgg5 { + x: FloatAgg1, + y: FloatAgg2, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + z: FloatAgg3, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} + +#[repr(C)] +pub struct FloatAgg6 { + x: i64, + y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + z: u8, +} + +#[repr(C)] +pub struct FloatAgg7 { + x: i64, + y: Floats, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + z: u8, + zz: f32, +} + +#[repr(C)] +pub struct A { + d: f64, +} +#[repr(C)] +pub struct B { + a: A, + f: f32, + d: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} +#[repr(C)] +pub struct C { + c: u8, + b: B, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} +#[repr(C)] +pub struct D { + x: f64, +} +#[repr(C)] +pub struct E { + x: i32, + d: D, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} +#[repr(C)] +pub struct F { + a: u8, + b: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} +#[repr(C)] +pub struct G { + a: u8, + b: u8, + c: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + d: f32, + e: f64, //~ WARNING repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type +} +// Should not warn on #[repr(packed)]. +#[repr(packed)] +pub struct H { + a: u8, + b: u8, + c: f64, + d: f32, + e: f64, +} +#[repr(C, packed)] +pub struct I { + a: u8, + b: u8, + c: f64, + d: f32, + e: f64, +} + +fn main() { } diff --git a/tests/ui/layout/reprc-power-alignment.stderr b/tests/ui/layout/reprc-power-alignment.stderr new file mode 100644 index 00000000000..18664e4d655 --- /dev/null +++ b/tests/ui/layout/reprc-power-alignment.stderr @@ -0,0 +1,112 @@ +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:18:5 + | +LL | c: f64, + | ^^^^^^ + | +note: the lint level is defined here + --> $DIR/reprc-power-alignment.rs:12:8 + | +LL | #[warn(uses_power_alignment)] + | ^^^^^^^^^^^^^^^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:45:5 + | +LL | b: f64, + | ^^^^^^ + | + = note: `#[warn(uses_power_alignment)]` on by default + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:52:5 + | +LL | y: f64, + | ^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:58:5 + | +LL | y: Floats, + | ^^^^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:65:5 + | +LL | y: FloatAgg2, + | ^^^^^^^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:66:5 + | +LL | z: FloatAgg2, + | ^^^^^^^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:72:5 + | +LL | y: FloatAgg2, + | ^^^^^^^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:78:5 + | +LL | y: FloatAgg2, + | ^^^^^^^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:79:5 + | +LL | z: FloatAgg3, + | ^^^^^^^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:85:5 + | +LL | y: Floats, + | ^^^^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:92:5 + | +LL | y: Floats, + | ^^^^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:105:3 + | +LL | d: f64, + | ^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:110:3 + | +LL | b: B, + | ^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:119:3 + | +LL | d: D, + | ^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:124:3 + | +LL | b: f64, + | ^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:130:5 + | +LL | c: f64, + | ^^^^^^ + +warning: repr(C) does not follow the power alignment rule. This may affect platform C ABI compatibility for this type + --> $DIR/reprc-power-alignment.rs:132:5 + | +LL | e: f64, + | ^^^^^^ + +warning: 17 warnings emitted + diff --git a/tests/ui/layout/valid_range_oob.stderr b/tests/ui/layout/valid_range_oob.stderr index 9c360b2cd6e..1a0c3841250 100644 --- a/tests/ui/layout/valid_range_oob.stderr +++ b/tests/ui/layout/valid_range_oob.stderr @@ -5,4 +5,4 @@ error: the compiler unexpectedly panicked. this is a bug. query stack during panic: #0 [layout_of] computing layout of `Foo` #1 [eval_to_allocation_raw] const-evaluating + checking `FOO` -end of query stack +... and 2 other queries... use `env RUST_BACKTRACE=1` to see the full query stack diff --git a/tests/ui/lint/clashing-extern-fn.rs b/tests/ui/lint/clashing-extern-fn.rs index a12fe81eecd..9bbb20246df 100644 --- a/tests/ui/lint/clashing-extern-fn.rs +++ b/tests/ui/lint/clashing-extern-fn.rs @@ -248,6 +248,7 @@ mod sameish_members { mod same_sized_members_clash { mod a { + #[allow(uses_power_alignment)] #[repr(C)] struct Point3 { x: f32, diff --git a/tests/ui/lint/clashing-extern-fn.stderr b/tests/ui/lint/clashing-extern-fn.stderr index b30dd476a1d..48dd1adbc1f 100644 --- a/tests/ui/lint/clashing-extern-fn.stderr +++ b/tests/ui/lint/clashing-extern-fn.stderr @@ -1,5 +1,5 @@ warning: `extern` block uses type `Option<TransparentNoNiche>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:482:55 + --> $DIR/clashing-extern-fn.rs:483:55 | LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoNiche>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -9,7 +9,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN = note: `#[warn(improper_ctypes)]` on by default warning: `extern` block uses type `Option<UnsafeCell<NonZero<usize>>>`, which is not FFI-safe - --> $DIR/clashing-extern-fn.rs:486:46 + --> $DIR/clashing-extern-fn.rs:487:46 | LL | fn hidden_niche_unsafe_cell() -> Option<UnsafeCell<NonZero<usize>>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not FFI-safe @@ -151,7 +151,7 @@ LL | fn draw_point(p: Point); found `unsafe extern "C" fn(sameish_members::b::Point)` warning: `origin` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:269:13 + --> $DIR/clashing-extern-fn.rs:270:13 | LL | fn origin() -> Point3; | ---------------------- `origin` previously declared here @@ -163,7 +163,7 @@ LL | fn origin() -> Point3; found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` warning: `transparent_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:292:13 + --> $DIR/clashing-extern-fn.rs:293:13 | LL | fn transparent_incorrect() -> T; | -------------------------------- `transparent_incorrect` previously declared here @@ -175,7 +175,7 @@ LL | fn transparent_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `missing_return_type` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:310:13 + --> $DIR/clashing-extern-fn.rs:311:13 | LL | fn missing_return_type() -> usize; | ---------------------------------- `missing_return_type` previously declared here @@ -187,7 +187,7 @@ LL | fn missing_return_type(); found `unsafe extern "C" fn()` warning: `non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:328:13 + --> $DIR/clashing-extern-fn.rs:329:13 | LL | fn non_zero_usize() -> core::num::NonZero<usize>; | ------------------------------------------------- `non_zero_usize` previously declared here @@ -199,7 +199,7 @@ LL | fn non_zero_usize() -> usize; found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:330:13 + --> $DIR/clashing-extern-fn.rs:331:13 | LL | fn non_null_ptr() -> core::ptr::NonNull<usize>; | ----------------------------------------------- `non_null_ptr` previously declared here @@ -211,7 +211,7 @@ LL | fn non_null_ptr() -> *const usize; found `unsafe extern "C" fn() -> *const usize` warning: `option_non_zero_usize_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:424:13 + --> $DIR/clashing-extern-fn.rs:425:13 | LL | fn option_non_zero_usize_incorrect() -> usize; | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here @@ -223,7 +223,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `option_non_null_ptr_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:426:13 + --> $DIR/clashing-extern-fn.rs:427:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here @@ -235,7 +235,7 @@ LL | fn option_non_null_ptr_incorrect() -> *const isize; found `unsafe extern "C" fn() -> *const isize` warning: `hidden_niche_transparent_no_niche` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:482:13 + --> $DIR/clashing-extern-fn.rs:483:13 | LL | fn hidden_niche_transparent_no_niche() -> usize; | ------------------------------------------------ `hidden_niche_transparent_no_niche` previously declared here @@ -247,7 +247,7 @@ LL | fn hidden_niche_transparent_no_niche() -> Option<TransparentNoN found `unsafe extern "C" fn() -> Option<TransparentNoNiche>` warning: `hidden_niche_unsafe_cell` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:486:13 + --> $DIR/clashing-extern-fn.rs:487:13 | LL | fn hidden_niche_unsafe_cell() -> usize; | --------------------------------------- `hidden_niche_unsafe_cell` previously declared here diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr index fd434eacf3d..e1c12cfd1a5 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/allow.stderr @@ -7,6 +7,8 @@ LL | dbg!(String::new().as_ptr()); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here --> $DIR/allow.rs:7:12 @@ -23,6 +25,8 @@ LL | dbg!(String::new().as_ptr()); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here --> $DIR/allow.rs:18:12 diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr index d1615b76d82..41c6cdd0e3e 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/calls.stderr @@ -7,6 +7,8 @@ LL | let ptr = cstring().as_ptr(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here --> $DIR/calls.rs:1:9 @@ -23,6 +25,8 @@ LL | let ptr = cstring().as_ptr(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `CString` will be dropped @@ -34,6 +38,8 @@ LL | let _ptr: *const u8 = cstring().as_ptr().cast(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `CString` will be dropped @@ -45,6 +51,8 @@ LL | let _ptr: *const u8 = { cstring() }.as_ptr().cast(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `CString` will be dropped @@ -56,6 +64,8 @@ LL | let _ptr: *const u8 = { cstring().as_ptr() }.cast(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: aborting due to 5 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr index 5289fbb8723..d4126ba231f 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/cstring-as-ptr.stderr @@ -15,6 +15,8 @@ LL | let s = CString::new("some text").unwrap().as_ptr(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here --> $DIR/cstring-as-ptr.rs:2:9 @@ -34,6 +36,8 @@ LL | mymacro!(); | ---------- in this macro invocation | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> = note: this error originates in the macro `mymacro` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr index 0de794f6ae2..aace55e92cf 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/example-from-issue123613.stderr @@ -7,6 +7,8 @@ LL | let str1 = String::with_capacity(MAX_PATH).as_mut_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_mut_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here --> $DIR/example-from-issue123613.rs:1:9 @@ -23,6 +25,8 @@ LL | let str2 = String::from("TotototototototototototototototototoT").as_ptr | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr index 5d401c89c0c..976334ddef9 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/ext.stderr @@ -7,6 +7,8 @@ LL | let _ptr1 = Vec::<u32>::new().as_ptr().dbg(); | this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec<u32>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec<u32>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here --> $DIR/ext.rs:1:9 @@ -23,6 +25,8 @@ LL | let _ptr2 = vec![0].as_ptr().foo(); | this `Vec<u32>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u32>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec<u32>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec<u32>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr index 11c052c158e..a86a69bc39a 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/methods.stderr @@ -7,6 +7,8 @@ LL | vec![0u8].as_ptr(); | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec<u8>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec<u8>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here --> $DIR/methods.rs:1:9 @@ -23,6 +25,8 @@ LL | vec![0u8].as_mut_ptr(); | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_mut_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec<u8>` to lives at least as long as the pointer returned by the call to `as_mut_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec<u8>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: aborting due to 2 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr index d2e9ac8c4e9..e8994703cab 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/temporaries.stderr @@ -7,6 +7,8 @@ LL | string().as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here --> $DIR/temporaries.rs:2:9 @@ -23,6 +25,8 @@ LL | "hello".to_string().as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -34,6 +38,8 @@ LL | (string() + "hello").as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -45,6 +51,8 @@ LL | (if true { String::new() } else { "hello".into() }).as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -58,6 +66,8 @@ LL | .as_ptr(); | ^^^^^^ this pointer will immediately be invalid | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -71,6 +81,8 @@ LL | .as_ptr(); | ^^^^^^ this pointer will immediately be invalid | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `String` will be dropped @@ -82,6 +94,8 @@ LL | { string() }.as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped @@ -93,6 +107,8 @@ LL | vec![0u8].as_ptr(); | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec<u8>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec<u8>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: aborting due to 8 previous errors diff --git a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr index 250ed6dc9e3..fab2459b53f 100644 --- a/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr +++ b/tests/ui/lint/dangling-pointers-from-temporaries/types.stderr @@ -7,6 +7,8 @@ LL | declval::<CString>().as_ptr(); | this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `CString` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `CString` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> note: the lint level is defined here --> $DIR/types.rs:1:9 @@ -23,6 +25,8 @@ LL | declval::<String>().as_ptr(); | this `String` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `String` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `String` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `String` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Vec<u8>` will be dropped @@ -34,6 +38,8 @@ LL | declval::<Vec<u8>>().as_ptr(); | this `Vec<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec<u8>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec<u8>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<CString>` will be dropped @@ -45,6 +51,8 @@ LL | declval::<Box<CString>>().as_ptr(); | this `Box<CString>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CString>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<CString>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<CString>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<[u8]>` will be dropped @@ -56,6 +64,8 @@ LL | declval::<Box<[u8]>>().as_ptr(); | this `Box<[u8]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<[u8]>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<[u8]>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<str>` will be dropped @@ -67,6 +77,8 @@ LL | declval::<Box<str>>().as_ptr(); | this `Box<str>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<str>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<str>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<str>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<CStr>` will be dropped @@ -78,6 +90,8 @@ LL | declval::<Box<CStr>>().as_ptr(); | this `Box<CStr>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<CStr>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<CStr>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<CStr>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `[u8; 10]` will be dropped @@ -89,6 +103,8 @@ LL | declval::<[u8; 10]>().as_ptr(); | this `[u8; 10]` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `[u8; 10]` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `[u8; 10]` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `[u8; 10]` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<[u8; 10]>` will be dropped @@ -100,6 +116,8 @@ LL | declval::<Box<[u8; 10]>>().as_ptr(); | this `Box<[u8; 10]>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<[u8; 10]>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<[u8; 10]>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<[u8; 10]>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<Vec<u8>>` will be dropped @@ -111,6 +129,8 @@ LL | declval::<Box<Vec<u8>>>().as_ptr(); | this `Box<Vec<u8>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Vec<u8>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<Vec<u8>>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<Vec<u8>>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<String>` will be dropped @@ -122,6 +142,8 @@ LL | declval::<Box<String>>().as_ptr(); | this `Box<String>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<String>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<String>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<String>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Box<Box<Box<Box<[u8]>>>>` will be dropped @@ -133,6 +155,8 @@ LL | declval::<Box<Box<Box<Box<[u8]>>>>>().as_ptr(); | this `Box<Box<Box<Box<[u8]>>>>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Box<Box<Box<Box<[u8]>>>>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Box<Box<Box<Box<[u8]>>>>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Box<Box<Box<Box<[u8]>>>>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Cell<u8>` will be dropped @@ -144,6 +168,8 @@ LL | declval::<Cell<u8>>().as_ptr(); | this `Cell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Cell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Cell<u8>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Cell<u8>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `MaybeUninit<u8>` will be dropped @@ -155,6 +181,8 @@ LL | declval::<MaybeUninit<u8>>().as_ptr(); | this `MaybeUninit<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `MaybeUninit<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `MaybeUninit<u8>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `MaybeUninit<u8>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `Vec<AsPtrFake>` will be dropped @@ -166,6 +194,8 @@ LL | declval::<Vec<AsPtrFake>>().as_ptr(); | this `Vec<AsPtrFake>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `as_ptr` the `Vec<AsPtrFake>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `Vec<AsPtrFake>` to lives at least as long as the pointer returned by the call to `as_ptr` + = help: in particular, if this pointer is returned from the current function, binding the `Vec<AsPtrFake>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `UnsafeCell<u8>` will be dropped @@ -177,6 +207,8 @@ LL | declval::<UnsafeCell<u8>>().get(); | this `UnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `get` the `UnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `UnsafeCell<u8>` to lives at least as long as the pointer returned by the call to `get` + = help: in particular, if this pointer is returned from the current function, binding the `UnsafeCell<u8>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: a dangling pointer will be produced because the temporary `SyncUnsafeCell<u8>` will be dropped @@ -188,6 +220,8 @@ LL | declval::<SyncUnsafeCell<u8>>().get(); | this `SyncUnsafeCell<u8>` is deallocated at the end of the statement, bind it to a variable to extend its lifetime | = note: pointers do not have a lifetime; when calling `get` the `SyncUnsafeCell<u8>` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned + = help: you must make sure that the variable you bind the `SyncUnsafeCell<u8>` to lives at least as long as the pointer returned by the call to `get` + = help: in particular, if this pointer is returned from the current function, binding the `SyncUnsafeCell<u8>` inside the function will not suffice = help: for more information, see <https://doc.rust-lang.org/reference/destructors.html> error: aborting due to 17 previous errors diff --git a/tests/ui/lint/dead-code/lint-dead-code-2.rs b/tests/ui/lint/dead-code/lint-dead-code-2.rs index 6bfa4d96f71..c82088ec54b 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-2.rs +++ b/tests/ui/lint/dead-code/lint-dead-code-2.rs @@ -1,6 +1,6 @@ #![allow(unused_variables)] #![deny(dead_code)] -#![feature(rustc_attrs, start)] +#![feature(rustc_attrs)] struct Foo; @@ -21,21 +21,16 @@ fn live_fn() {} fn dead_fn() {} //~ ERROR: function `dead_fn` is never used -#[rustc_main] -fn dead_fn2() {} //~ ERROR: function `dead_fn2` is never used - fn used_fn() {} -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +#[rustc_main] +fn actual_main() { used_fn(); let foo = Foo; foo.bar2(); - 0 } // this is not main fn main() { //~ ERROR: function `main` is never used dead_fn(); - dead_fn2(); } diff --git a/tests/ui/lint/dead-code/lint-dead-code-2.stderr b/tests/ui/lint/dead-code/lint-dead-code-2.stderr index 85af553c986..4a5f3b8a687 100644 --- a/tests/ui/lint/dead-code/lint-dead-code-2.stderr +++ b/tests/ui/lint/dead-code/lint-dead-code-2.stderr @@ -10,17 +10,11 @@ note: the lint level is defined here LL | #![deny(dead_code)] | ^^^^^^^^^ -error: function `dead_fn2` is never used - --> $DIR/lint-dead-code-2.rs:25:4 - | -LL | fn dead_fn2() {} - | ^^^^^^^^ - error: function `main` is never used - --> $DIR/lint-dead-code-2.rs:38:4 + --> $DIR/lint-dead-code-2.rs:34:4 | LL | fn main() { | ^^^^ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/lint/wide_pointer_comparisons.stderr b/tests/ui/lint/wide_pointer_comparisons.stderr index 7fe382393d7..78548e308ed 100644 --- a/tests/ui/lint/wide_pointer_comparisons.stderr +++ b/tests/ui/lint/wide_pointer_comparisons.stderr @@ -615,7 +615,7 @@ warning: ambiguous wide pointer comparison, the comparison includes metadata whi --> $DIR/wide_pointer_comparisons.rs:169:37 | LL | ($a:expr, $b:expr) => { $a == $b } - | ^^ + | ^^^^^^^^ ... LL | cmp!(&a, &b); | ------------ in this macro invocation diff --git a/tests/ui/macros/not-utf8.rs b/tests/ui/macros/not-utf8.rs index 8100d65a9f8..ad8ac39d230 100644 --- a/tests/ui/macros/not-utf8.rs +++ b/tests/ui/macros/not-utf8.rs @@ -3,5 +3,5 @@ //@ reference: input.encoding.invalid fn foo() { - include!("not-utf8.bin") + include!("not-utf8.bin"); } diff --git a/tests/ui/macros/not-utf8.stderr b/tests/ui/macros/not-utf8.stderr index 0d587cab5f3..17ee8197ac8 100644 --- a/tests/ui/macros/not-utf8.stderr +++ b/tests/ui/macros/not-utf8.stderr @@ -1,9 +1,14 @@ -error: couldn't read $DIR/not-utf8.bin: stream did not contain valid UTF-8 +error: couldn't read `$DIR/not-utf8.bin`: stream did not contain valid UTF-8 --> $DIR/not-utf8.rs:6:5 | -LL | include!("not-utf8.bin") +LL | include!("not-utf8.bin"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | +note: byte `193` is not valid utf-8 + --> $DIR/not-utf8.bin:1:1 + | +LL | �|�␂!5�cc␕␂�Ӻi��WWj�ȥ�'�}�␒�J�ȉ��W�␞O�@����␜w�V���LO����␔[ ␃_�'���SQ�~ذ��ų&��- ��lN~��!@␌ _#���kQ��h�␝�:�... + | ^ = note: this error originates in the macro `include` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 1 previous error diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs index 37d94830db2..2a27164f9cb 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/assert-with-custom-errors-does-not-create-unnecessary-code.rs @@ -1,4 +1,6 @@ -//@ compile-flags: --test +// -Zpanic_abort_tests makes this test work on panic=abort targets and +// it's a no-op on panic=unwind targets +//@ compile-flags: --test -Zpanic_abort_tests //@ run-pass #![feature(core_intrinsics, generic_assert)] diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs index 86cc7adb90d..254d59076e5 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/feature-gate-generic_assert.rs @@ -1,4 +1,6 @@ -//@ compile-flags: --test +// -Zpanic_abort_tests makes this test work on panic=abort targets and +// it's a no-op on panic=unwind targets +//@ compile-flags: --test -Zpanic_abort_tests // ignore-tidy-linelength //@ run-pass diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr deleted file mode 100644 index f8672d755b9..00000000000 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.both.stderr +++ /dev/null @@ -1,169 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:8:17 - | -LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { - | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` - | | - | types differ in mutability - | - = note: expected reference `&Option<{integer}>` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:11: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:15:27 - | -LL | let _: &mut u32 = x; - | -------- ^ types differ in mutability - | | - | expected due to this - | - = note: expected mutable reference `&mut u32` - found reference `&{integer}` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:18: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:24: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:27: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9 - | -LL | let &mut _ = &&0; - | ^^^^^^ --- this expression has type `&&{integer}` - | | - | types differ in mutability - | - = note: expected reference `&&{integer}` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:34:9 - | -LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; - | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` - | | - | types differ in mutability - | - = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45: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:48: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:51: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:60: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:64: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[E0277]: the trait bound `&_: main::Ref` is not satisfied - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:82:14 - | -LL | let &_ = generic(); - | ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_` - | - = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]` -note: required by a bound in `generic` - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:68:19 - | -LL | fn generic<R: Ref>() -> R { - | ^^^ required by this bound in `generic` - -error: aborting due to 15 previous errors - -Some errors have detailed explanations: E0277, E0308, E0658. -For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr deleted file mode 100644 index a37316b3097..00000000000 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.classic.stderr +++ /dev/null @@ -1,199 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:8:17 - | -LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { - | ^^^^^ - | - = note: cannot match inherited `&` with `&mut` pattern -help: replace this `&mut` pattern with `&` - | -LL | if let Some(&Some(&_)) = &Some(&Some(0)) { - | ~ - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:11:23 - | -LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - | ^^^^^ - | - = note: cannot match inherited `&` with `&mut` pattern -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:15:27 - | -LL | let _: &mut u32 = x; - | -------- ^ types differ in mutability - | | - | expected due to this - | - = note: expected mutable reference `&mut u32` - found reference `&{integer}` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:18:23 - | -LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { - | ^^^^^ - | - = note: cannot match inherited `&` with `&mut` pattern -help: replace this `&mut` pattern with `&` - | -LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) { - | ~ - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21:29 - | -LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { - | ^^^^^ - | - = note: cannot match inherited `&` with `&mut` pattern -help: replace this `&mut` pattern with `&` - | -LL | if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) { - | ~ - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:24:17 - | -LL | if let Some(&mut Some(x)) = &Some(Some(0)) { - | ^^^^^ - | - = note: cannot match inherited `&` with `&mut` pattern -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:27:17 - | -LL | if let Some(&mut Some(x)) = &Some(Some(0)) { - | ^^^^^ - | - = note: cannot match inherited `&` with `&mut` pattern -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:31:9 - | -LL | let &mut _ = &&0; - | ^^^^^^ --- this expression has type `&&{integer}` - | | - | types differ in mutability - | - = note: expected reference `&&{integer}` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:34:9 - | -LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; - | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` - | | - | types differ in mutability - | - = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:37:17 - | -LL | if let Some(&mut Some(&_)) = &Some(&mut Some(0)) { - | ^^^^^ - | - = note: cannot match inherited `&` with `&mut` pattern -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:41:22 - | -LL | if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { - | ^^^^^ - | - = note: cannot match inherited `&` with `&mut` pattern -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:45: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:48: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:51: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:60: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:64: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[E0277]: the trait bound `&_: main::Ref` is not satisfied - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:82:14 - | -LL | let &_ = generic(); - | ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_` - | - = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]` -note: required by a bound in `generic` - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:68:19 - | -LL | fn generic<R: Ref>() -> R { - | ^^^ required by this bound in `generic` - -error: aborting due to 17 previous errors - -Some errors have detailed explanations: E0277, E0308, E0658. -For more information about an error, try `rustc --explain E0277`. 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 deleted file mode 100644 index fd616807b28..00000000000 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs +++ /dev/null @@ -1,83 +0,0 @@ -//@ edition: 2024 -//@ revisions: classic structural both -#![allow(incomplete_features)] -#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))] - -pub fn main() { - if let Some(&mut Some(&_)) = &Some(&Some(0)) { - //~^ ERROR: mismatched types - } - if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { - //~^ ERROR: mismatched types - } - 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 - } - if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { - //~^ ERROR: mismatched types - } - if let Some(&mut Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types - } - if let Some(&mut Some(x)) = &Some(Some(0)) { - //~^ ERROR: mismatched types - } - - let &mut _ = &&0; - //~^ ERROR: mismatched types - - let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; - //~^ ERROR: mismatched types - - if let Some(&mut Some(&_)) = &Some(&mut Some(0)) { - //[classic]~^ ERROR: mismatched types - } - - if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { - //[classic]~^ ERROR: mismatched types - } - - 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 - - if let Some(&mut _) = &mut Some(&0) { - //[structural]~^ ERROR - } - - 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; - - fn generic<R: Ref>() -> R { - R::meow() - } - - trait Ref: Sized { - fn meow() -> Self; - } - - impl Ref for &'static mut [(); 0] { - fn meow() -> Self { - &mut [] - } - } - - let &_ = generic(); //~ERROR: the trait bound `&_: main::Ref` is not satisfied [E0277] -} diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr deleted file mode 100644 index 2f62e9974fa..00000000000 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.structural.stderr +++ /dev/null @@ -1,180 +0,0 @@ -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:8:17 - | -LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { - | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` - | | - | types differ in mutability - | - = note: expected reference `&Option<{integer}>` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:11: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:15:27 - | -LL | let _: &mut u32 = x; - | -------- ^ types differ in mutability - | | - | expected due to this - | - = note: expected mutable reference `&mut u32` - found reference `&{integer}` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:18: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:21: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:24: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:27: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 _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9 - | -LL | let &mut _ = &&0; - | ^^^^^^ --- this expression has type `&&{integer}` - | | - | types differ in mutability - | - = note: expected reference `&&{integer}` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:34:9 - | -LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; - | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` - | | - | types differ in mutability - | - = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` - found mutable reference `&mut _` - -error[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:45: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:48: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:51: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[E0308]: mismatched types - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:54:17 - | -LL | if let Some(&mut _) = &mut Some(&0) { - | ^^^^^^ ------------- this expression has type `&mut Option<&{integer}>` - | | - | types differ in mutability - | - = note: expected reference `&{integer}` - found mutable reference `&mut _` - -error[E0658]: binding cannot be both mutable and by-reference - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:60: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:64: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[E0277]: the trait bound `&_: main::Ref` is not satisfied - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:82:14 - | -LL | let &_ = generic(); - | ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_` - | - = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]` -note: required by a bound in `generic` - --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:68:19 - | -LL | fn generic<R: Ref>() -> R { - | ^^^ required by this bound in `generic` - -error: aborting due to 16 previous errors - -Some errors have detailed explanations: E0277, E0308, E0658. -For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/mir/lint/storage-live.stderr b/tests/ui/mir/lint/storage-live.stderr index c7012319512..651b8e2327e 100644 --- a/tests/ui/mir/lint/storage-live.stderr +++ b/tests/ui/mir/lint/storage-live.stderr @@ -1,4 +1,4 @@ -error: internal compiler error: broken MIR in Item(DefId(0:8 ~ storage_live[HASH]::multiple_storage)) (after pass CheckPackedRef) at bb0[1]: +error: internal compiler error: broken MIR in Item(DefId(0:8 ~ storage_live[HASH]::multiple_storage)) (after pass CheckForceInline) at bb0[1]: StorageLive(_1) which already has storage here --> $DIR/storage-live.rs:23:13 | diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed new file mode 100644 index 00000000000..7383ab177dc --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.fixed @@ -0,0 +1,12 @@ +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[current] run-rustfix +fn main() { + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); + //[current]~^ ERROR type mismatch in closure arguments + //[next]~^^ ERROR expected a `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found + let _ = (-10..=10).find(|x: &i32| x.signum() == 0); + //[current]~^ ERROR type mismatch in closure arguments + //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` +} diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr index e52e095e9f7..c35d70a635c 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.stderr +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.current.stderr @@ -1,5 +1,5 @@ error[E0631]: type mismatch in closure arguments - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:3:24 + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:24 | LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); | ^^^^ -------- found signature defined here @@ -16,7 +16,7 @@ LL | let _ = (-10..=10).find(|x: &i32| x.signum() == 0); | + error[E0631]: type mismatch in closure arguments - --> $DIR/closure-arg-type-mismatch-issue-45727.rs:4:24 + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:24 | LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); | ^^^^ ----------- found signature defined here diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed deleted file mode 100644 index e6e3e1551e9..00000000000 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.fixed +++ /dev/null @@ -1,5 +0,0 @@ -//@ run-rustfix -fn main() { - let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments - let _ = (-10..=10).find(|x: &i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments -} diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr new file mode 100644 index 00000000000..6104a089337 --- /dev/null +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.next.stderr @@ -0,0 +1,24 @@ +error[E0277]: expected a `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}` + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:6:29 + | +LL | let _ = (-10..=10).find(|x: i32| x.signum() == 0); + | ---- ^^^^^^^^^^^^^^^^^^^^^^^^ expected an `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}` + | | + | required by a bound introduced by this call + | + = help: the trait `for<'a> FnMut(&'a <RangeInclusive<{integer}> as Iterator>::Item)` is not implemented for closure `{closure@$DIR/closure-arg-type-mismatch-issue-45727.rs:6:29: 6:37}` + = note: expected a closure with arguments `(i32,)` + found a closure with arguments `(&<RangeInclusive<{integer}> as Iterator>::Item,)` +note: required by a bound in `find` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error[E0271]: expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` + --> $DIR/closure-arg-type-mismatch-issue-45727.rs:9:33 + | +LL | let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); + | ^^^^^^ expected `&&i32`, found integer + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`. diff --git a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs index 64e815606d4..668a1a7a29c 100644 --- a/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs +++ b/tests/ui/mismatched_types/closure-arg-type-mismatch-issue-45727.rs @@ -1,5 +1,12 @@ -//@ run-rustfix +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[current] run-rustfix fn main() { - let _ = (-10..=10).find(|x: i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments - let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); //~ ERROR type mismatch in closure arguments + let _ = (-10..=10).find(|x: i32| x.signum() == 0); + //[current]~^ ERROR type mismatch in closure arguments + //[next]~^^ ERROR expected a `FnMut(&<RangeInclusive<{integer}> as Iterator>::Item)` closure, found + let _ = (-10..=10).find(|x: &&&i32| x.signum() == 0); + //[current]~^ ERROR type mismatch in closure arguments + //[next]~^^ ERROR expected `RangeInclusive<{integer}>` to be an iterator that yields `&&i32`, but it yields `{integer}` } diff --git a/tests/ui/modules/path-no-file-name.rs b/tests/ui/modules/path-no-file-name.rs index 23127346e02..753a0950123 100644 --- a/tests/ui/modules/path-no-file-name.rs +++ b/tests/ui/modules/path-no-file-name.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "\.:.*\(" -> ".: $$ACCESS_DENIED_MSG (" +//@ normalize-stderr: "\.`:.*\(" -> ".`: $$ACCESS_DENIED_MSG (" //@ normalize-stderr: "os error \d+" -> "os error $$ACCESS_DENIED_CODE" #[path = "."] diff --git a/tests/ui/modules/path-no-file-name.stderr b/tests/ui/modules/path-no-file-name.stderr index 834e8ea6b03..6274ecfed13 100644 --- a/tests/ui/modules/path-no-file-name.stderr +++ b/tests/ui/modules/path-no-file-name.stderr @@ -1,4 +1,4 @@ -error: couldn't read $DIR/.: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) +error: couldn't read `$DIR/.`: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) --> $DIR/path-no-file-name.rs:5:1 | LL | mod m; diff --git a/tests/ui/parser/issues/issue-5806.rs b/tests/ui/parser/issues/issue-5806.rs index dbd53a7adc4..1a819e22197 100644 --- a/tests/ui/parser/issues/issue-5806.rs +++ b/tests/ui/parser/issues/issue-5806.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "parser:.*\(" -> "parser: $$ACCESS_DENIED_MSG (" +//@ normalize-stderr: "parser`:.*\(" -> "parser`: $$ACCESS_DENIED_MSG (" //@ normalize-stderr: "os error \d+" -> "os error $$ACCESS_DENIED_CODE" #[path = "../parser"] diff --git a/tests/ui/parser/issues/issue-5806.stderr b/tests/ui/parser/issues/issue-5806.stderr index 4b025bd19a0..88cc982baf2 100644 --- a/tests/ui/parser/issues/issue-5806.stderr +++ b/tests/ui/parser/issues/issue-5806.stderr @@ -1,4 +1,4 @@ -error: couldn't read $DIR/../parser: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) +error: couldn't read `$DIR/../parser`: $ACCESS_DENIED_MSG (os error $ACCESS_DENIED_CODE) --> $DIR/issue-5806.rs:5:1 | LL | mod foo; diff --git a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr index 76259b40a93..dda37d83282 100644 --- a/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr +++ b/tests/ui/parser/issues/issue-65122-mac-invoc-in-mut-patterns.stderr @@ -30,7 +30,7 @@ error: `mut` must be followed by a named binding --> $DIR/issue-65122-mac-invoc-in-mut-patterns.rs:13:13 | LL | let mut $eval = (); - | ^^^ + | ^^^^ ... LL | mac2! { does_not_exist!() } | --------------------------- in this macro invocation @@ -40,7 +40,7 @@ LL | mac2! { does_not_exist!() } help: remove the `mut` prefix | LL - let mut $eval = (); -LL + let $eval = (); +LL + let $eval = (); | error: cannot find macro `does_not_exist` in this scope diff --git a/tests/ui/parser/mod_file_with_path_attr.rs b/tests/ui/parser/mod_file_with_path_attr.rs index ff964f750e2..b7f4a9c6ae0 100644 --- a/tests/ui/parser/mod_file_with_path_attr.rs +++ b/tests/ui/parser/mod_file_with_path_attr.rs @@ -1,4 +1,4 @@ -//@ normalize-stderr: "not_a_real_file.rs:.*\(" -> "not_a_real_file.rs: $$FILE_NOT_FOUND_MSG (" +//@ normalize-stderr: "not_a_real_file.rs`:.*\(" -> "not_a_real_file.rs`: $$FILE_NOT_FOUND_MSG (" #[path = "not_a_real_file.rs"] mod m; //~ ERROR not_a_real_file.rs diff --git a/tests/ui/parser/mod_file_with_path_attr.stderr b/tests/ui/parser/mod_file_with_path_attr.stderr index 9ccb775daab..ef8a715712b 100644 --- a/tests/ui/parser/mod_file_with_path_attr.stderr +++ b/tests/ui/parser/mod_file_with_path_attr.stderr @@ -1,4 +1,4 @@ -error: couldn't read $DIR/not_a_real_file.rs: $FILE_NOT_FOUND_MSG (os error 2) +error: couldn't read `$DIR/not_a_real_file.rs`: $FILE_NOT_FOUND_MSG (os error 2) --> $DIR/mod_file_with_path_attr.rs:4:1 | LL | mod m; diff --git a/tests/ui/pattern/no_ref_mut_behind_and.rs b/tests/ui/pattern/no_ref_mut_behind_and.rs deleted file mode 100644 index c18d64904d0..00000000000 --- a/tests/ui/pattern/no_ref_mut_behind_and.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ 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/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr index a8b81394110..c6246114075 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.classic.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:6:29 + --> $DIR/borrowck-errors.rs:9:29 | LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { | - ^^^^^^^^^^^^^^^^^^^ @@ -14,7 +14,7 @@ LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { | error[E0596]: cannot borrow data in a `&` reference as mutable - --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:11:10 + --> $DIR/borrowck-errors.rs:14:10 | LL | let &ref mut x = &0; | ^^^^^^^^^ cannot borrow as mutable diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs index 79403b19365..a01e9ca2657 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.rs @@ -1,6 +1,9 @@ //@ edition: 2024 +//@ revisions: classic structural +//! Tests for pattern errors not handled by the pattern typing rules, but by borrowck. #![allow(incomplete_features)] -#![feature(ref_pat_eat_one_layer_2024)] +#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(&Some(x)) = Some(&Some(&mut 0)) { diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr new file mode 100644 index 00000000000..c6246114075 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/borrowck-errors.structural.stderr @@ -0,0 +1,25 @@ +error[E0507]: cannot move out of a shared reference + --> $DIR/borrowck-errors.rs:9:29 + | +LL | if let Some(&Some(x)) = Some(&Some(&mut 0)) { + | - ^^^^^^^^^^^^^^^^^^^ + | | + | data moved here + | move occurs because `x` has type `&mut u32`, which does not implement the `Copy` trait + | +help: consider removing the borrow + | +LL - if let Some(&Some(x)) = Some(&Some(&mut 0)) { +LL + if let Some(Some(x)) = Some(&Some(&mut 0)) { + | + +error[E0596]: cannot borrow data in a `&` reference as mutable + --> $DIR/borrowck-errors.rs:14:10 + | +LL | let &ref mut x = &0; + | ^^^^^^^^^ cannot borrow as mutable + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0507, E0596. +For more information about an error, try `rustc --explain E0507`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr new file mode 100644 index 00000000000..89a52ba7d1d --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.classic.stderr @@ -0,0 +1,58 @@ +error[E0308]: mismatched types + --> $DIR/cannot-mutably-deref-shared-ref.rs:9:9 + | +LL | let &mut _ = &&0; + | ^^^^^^ --- this expression has type `&&{integer}` + | | + | types differ in mutability + | + = note: expected reference `&&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/cannot-mutably-deref-shared-ref.rs:12:9 + | +LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; + | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/cannot-mutably-deref-shared-ref.rs:15: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/cannot-mutably-deref-shared-ref.rs:18: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/cannot-mutably-deref-shared-ref.rs:21: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: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs new file mode 100644 index 00000000000..e22bd1f8f6c --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.rs @@ -0,0 +1,23 @@ +//@ edition: 2024 +//@ revisions: classic structural +//! Test that `&mut` patterns don't match shared reference types under new typing rules in Rust 2024 +#![allow(incomplete_features)] +#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] + +pub fn main() { + let &mut _ = &&0; + //~^ ERROR: mismatched types + + let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; + //~^ ERROR: mismatched types + + 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 +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr new file mode 100644 index 00000000000..89a52ba7d1d --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/cannot-mutably-deref-shared-ref.structural.stderr @@ -0,0 +1,58 @@ +error[E0308]: mismatched types + --> $DIR/cannot-mutably-deref-shared-ref.rs:9:9 + | +LL | let &mut _ = &&0; + | ^^^^^^ --- this expression has type `&&{integer}` + | | + | types differ in mutability + | + = note: expected reference `&&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/cannot-mutably-deref-shared-ref.rs:12:9 + | +LL | let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0; + | ^^^^^^ ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + | | + | types differ in mutability + | + = note: expected reference `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/cannot-mutably-deref-shared-ref.rs:15: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/cannot-mutably-deref-shared-ref.rs:18: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/cannot-mutably-deref-shared-ref.rs:21: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: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.rs index bc12d69b105..bc12d69b105 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.rs diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.stderr index 132fe421a18..132fe421a18 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/feature-gate-ref_pat_eat_one_layer_2024.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/feature-gate-ref_pat_eat_one_layer_2024.stderr diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr new file mode 100644 index 00000000000..43560a18030 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.classic.stderr @@ -0,0 +1,23 @@ +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/mut-ref-mut.rs:11: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/mut-ref-mut.rs:15: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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs new file mode 100644 index 00000000000..786587984ba --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.rs @@ -0,0 +1,18 @@ +//@ edition: 2024 +//@ revisions: classic structural +//! Test diagnostics for binding with `mut` when the default binding mode is by-ref. +#![allow(incomplete_features)] +#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] + +pub fn main() { + 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/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr new file mode 100644 index 00000000000..43560a18030 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/mut-ref-mut.structural.stderr @@ -0,0 +1,23 @@ +error[E0658]: binding cannot be both mutable and by-reference + --> $DIR/mut-ref-mut.rs:11: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/mut-ref-mut.rs:15: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 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr new file mode 100644 index 00000000000..2bc3ecb7636 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.classic.stderr @@ -0,0 +1,111 @@ +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:15:17 + | +LL | if let Some(&mut x) = &Some(&mut 0) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&x) = &Some(&mut 0) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:19:17 + | +LL | if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&x)) = &Some(&mut Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:23:22 + | +LL | if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(Some(&x)) = &Some(Some(&mut 0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:28:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:31:23 + | +LL | if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &Some(&mut Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:34:23 + | +LL | if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(&_)) = &mut Some(&Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:37:29 + | +LL | if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(Some((&_)))) = &Some(Some(&mut Some(0))) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:40:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:43:17 + | +LL | if let Some(&mut Some(x)) = &Some(Some(0)) { + | ^^^^^ + | + = note: cannot match inherited `&` with `&mut` pattern +help: replace this `&mut` pattern with `&` + | +LL | if let Some(&Some(x)) = &Some(Some(0)) { + | ~ + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs new file mode 100644 index 00000000000..3535ba9c701 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.rs @@ -0,0 +1,46 @@ +//@ edition: 2024 +//@ revisions: classic structural +//! Test cases for poorly-typed patterns in edition 2024 which are caught by HIR typeck. These must +//! be separate from cases caught by MIR borrowck or the latter errors may not be emitted. +#![allow(incomplete_features)] +#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] + +pub fn main() { + if let Some(&mut x) = &mut Some(&0) { + //[structural]~^ ERROR: mismatched types + let _: &u32 = x; + } + + if let Some(&mut x) = &Some(&mut 0) { + //[classic]~^ ERROR: mismatched types + let _: &u32 = x; + } + if let Some(&mut Some(&x)) = &Some(&mut Some(0)) { + //[classic]~^ ERROR: mismatched types + let _: u32 = x; + } + if let Some(Some(&mut x)) = &Some(Some(&mut 0)) { + //[classic]~^ ERROR: mismatched types + let _: &u32 = x; + } + + if let Some(&mut Some(&_)) = &Some(&Some(0)) { + //~^ ERROR: mismatched types + } + if let Some(&Some(&mut _)) = &Some(&mut Some(0)) { + //~^ ERROR: mismatched types + } + if let Some(&Some(&mut _)) = &mut Some(&Some(0)) { + //~^ ERROR: mismatched types + } + if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) { + //~^ ERROR: mismatched types + } + if let Some(&mut Some(x)) = &Some(Some(0)) { + //~^ ERROR: mismatched types + } + if let Some(&mut Some(x)) = &Some(Some(0)) { + //~^ ERROR: mismatched types + } +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr new file mode 100644 index 00000000000..59d65553fae --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/pattern-errors.structural.stderr @@ -0,0 +1,89 @@ +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:10:17 + | +LL | if let Some(&mut x) = &mut Some(&0) { + | ^^^^^^ ------------- this expression has type `&mut Option<&{integer}>` + | | + | types differ in mutability + | + = note: expected reference `&{integer}` + found mutable reference `&mut _` +note: to declare a mutable binding use: `mut x` + --> $DIR/pattern-errors.rs:10:17 + | +LL | if let Some(&mut x) = &mut Some(&0) { + | ^^^^^^ +help: consider removing `&mut` from the pattern + | +LL | if let Some(x) = &mut Some(&0) { + | ~ + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:28:17 + | +LL | if let Some(&mut Some(&_)) = &Some(&Some(0)) { + | ^^^^^^^^^^^^^ --------------- this expression has type `&Option<&Option<{integer}>>` + | | + | types differ in mutability + | + = note: expected reference `&Option<{integer}>` + found mutable reference `&mut _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:31: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 _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:34: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 _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:37: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 _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:40: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 _` + +error[E0308]: mismatched types + --> $DIR/pattern-errors.rs:43: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 _` + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed index e69d169966b..4f4941975d8 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.fixed @@ -1,7 +1,11 @@ //@ edition: 2024 //@ run-rustfix +//@ revisions: classic structural +//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts +//! to bind by mutable reference. #![allow(incomplete_features)] -#![feature(ref_pat_eat_one_layer_2024)] +#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) { diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr index 8e135b65253..6c384a51fac 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.classic.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:7:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:11:31 | LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -7,7 +7,7 @@ LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:12:31 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31 | LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | - ^ @@ -15,7 +15,7 @@ LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:20:15 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:24:15 | LL | let &pat!(x) = &mut 0; | - ^ @@ -23,7 +23,7 @@ LL | let &pat!(x) = &mut 0; | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:24:19 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:19 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ @@ -31,7 +31,7 @@ LL | let &(ref mut a, ref mut b) = &mut (true, false); | help: replace this `&` with `&mut`: `&mut` error[E0596]: cannot borrow as mutable inside an `&` pattern - --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:24:30 + --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:30 | LL | let &(ref mut a, ref mut b) = &mut (true, false); | - ^ diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs index a300cbcd4df..b29bff7603f 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.rs @@ -1,7 +1,11 @@ //@ edition: 2024 //@ run-rustfix +//@ revisions: classic structural +//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts +//! to bind by mutable reference. #![allow(incomplete_features)] -#![feature(ref_pat_eat_one_layer_2024)] +#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed new file mode 100644 index 00000000000..4f4941975d8 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.fixed @@ -0,0 +1,33 @@ +//@ edition: 2024 +//@ run-rustfix +//@ revisions: classic structural +//! Tests for `&` patterns matched against `&mut` reference types where the inner pattern attempts +//! to bind by mutable reference. +#![allow(incomplete_features)] +#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] + +pub fn main() { + if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) { + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) { + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + } + + macro_rules! pat { + ($var:ident) => { ref mut $var }; + } + let &mut pat!(x) = &mut 0; + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut u8 = x; + + let &mut (ref mut a, ref mut b) = &mut (true, false); + //~^ ERROR: cannot borrow as mutable inside an `&` pattern + //~| ERROR: cannot borrow as mutable inside an `&` pattern + let _: &mut bool = a; + let _: &mut bool = b; +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr new file mode 100644 index 00000000000..6c384a51fac --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref-mut-inside-shared-ref-pat.structural.stderr @@ -0,0 +1,43 @@ +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:11:31 + | +LL | if let Some(&Some(ref mut x)) = &mut Some(Some(0)) { + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:16:31 + | +LL | if let &Some(Some(ref mut x)) = &mut Some(Some(0)) { + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:24:15 + | +LL | let &pat!(x) = &mut 0; + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:19 + | +LL | let &(ref mut a, ref mut b) = &mut (true, false); + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error[E0596]: cannot borrow as mutable inside an `&` pattern + --> $DIR/ref-mut-inside-shared-ref-pat.rs:28:30 + | +LL | let &(ref mut a, ref mut b) = &mut (true, false); + | - ^ + | | + | help: replace this `&` with `&mut`: `&mut` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs index afea249ffef..9372049a2b2 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021.rs @@ -1,9 +1,9 @@ //@ run-pass //@ edition: 2021 -//@ revisions: classic structural both +//@ revisions: classic structural #![allow(incomplete_features)] -#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let &Some(Some(x)) = &Some(&mut Some(0)) { diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.rs index d28567f2859..d28567f2859 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.rs diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.stderr index 1a921234ea0..1a921234ea0 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2021_fail.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/ref_pat_eat_one_layer_2021_fail.stderr diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.rs new file mode 100644 index 00000000000..cb8fdb489c0 --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.rs @@ -0,0 +1,30 @@ +//@ edition: 2024 +//@ revisions: with_impl without_impl +//@[with_impl] run-pass +//! Sanity check that experimental new pattern typing rules work as expected with trait selection + +fn main() { + fn generic<R: Ref>() -> (R, bool) { + R::meow() + } + + trait Ref: Sized { + fn meow() -> (Self, bool); + } + + #[cfg(with_impl)] + impl Ref for &'static [(); 0] { + fn meow() -> (Self, bool) { + (&[], false) + } + } + + impl Ref for &'static mut [(); 0] { + fn meow() -> (Self, bool) { + (&mut [], true) + } + } + + let (&_, b) = generic(); //[without_impl]~ ERROR: the trait bound `&_: main::Ref` is not satisfied [E0277] + assert!(!b); +} diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.without_impl.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.without_impl.stderr new file mode 100644 index 00000000000..83e45221fac --- /dev/null +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/trait-selection-sanity.without_impl.stderr @@ -0,0 +1,16 @@ +error[E0277]: the trait bound `&_: main::Ref` is not satisfied + --> $DIR/trait-selection-sanity.rs:28:19 + | +LL | let (&_, b) = generic(); + | ^^^^^^^^^ the trait `main::Ref` is not implemented for `&_` + | + = help: the trait `main::Ref` is implemented for `&'static mut [(); 0]` +note: required by a bound in `generic` + --> $DIR/trait-selection-sanity.rs:7:19 + | +LL | fn generic<R: Ref>() -> (R, bool) { + | ^^^ required by this bound in `generic` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs index b145446de0a..077b52d8f27 100644 --- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/experimental/well-typed-edition-2024.rs @@ -1,9 +1,11 @@ -//@ run-pass //@ edition: 2024 -//@ revisions: classic structural both +//@ revisions: classic structural +//@ run-pass +//! Test cases for well-typed patterns in edition 2024. These are in their own file to ensure we +//! pass both HIR typeck and MIR borrowck, as we may skip the latter if grouped with failing tests. #![allow(incomplete_features)] -#![cfg_attr(any(classic, both), feature(ref_pat_eat_one_layer_2024))] -#![cfg_attr(any(structural, both), feature(ref_pat_eat_one_layer_2024_structural))] +#![cfg_attr(classic, feature(ref_pat_eat_one_layer_2024))] +#![cfg_attr(structural, feature(ref_pat_eat_one_layer_2024_structural))] pub fn main() { if let Some(Some(&x)) = &Some(&Some(0)) { @@ -54,35 +56,4 @@ pub fn main() { if let Some(&Some(x)) = &mut Some(Some(0)) { let _: u32 = x; } - #[cfg(any(classic, both))] - if let Some(&mut x) = &mut Some(&0) { - let _: &u32 = x; - } - #[cfg(any(structural, both))] - if let Some(&mut x) = &Some(&mut 0) { - let _: &u32 = x; - } - - fn generic<R: Ref>() -> (R, bool) { - R::meow() - } - - trait Ref: Sized { - fn meow() -> (Self, bool); - } - - impl Ref for &'static [(); 0] { - fn meow() -> (Self, bool) { - (&[], false) - } - } - - impl Ref for &'static mut [(); 0] { - fn meow() -> (Self, bool) { - (&mut [], true) - } - } - - let (&_, b) = generic(); - assert!(!b); } diff --git a/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr b/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr index ba7573839ed..ee21b4c8d46 100644 --- a/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr +++ b/tests/ui/pattern/usefulness/issue-82772-match-box-as-struct.stderr @@ -2,7 +2,7 @@ error[E0451]: field `1` of struct `Box` is private --> $DIR/issue-82772-match-box-as-struct.rs:4:15 | LL | let Box { 1: _, .. }: Box<()>; - | ^^^^ private field + | ^ private field error: aborting due to 1 previous error diff --git a/tests/ui/print_type_sizes/anonymous.rs b/tests/ui/print_type_sizes/anonymous.rs index a3a32228088..7819e5ea767 100644 --- a/tests/ui/print_type_sizes/anonymous.rs +++ b/tests/ui/print_type_sizes/anonymous.rs @@ -1,14 +1,13 @@ -//@ compile-flags: -Z print-type-sizes +//@ compile-flags: -Z print-type-sizes --crate-type=lib //@ build-pass // All of the types that occur in this function are uninteresting, in // that one cannot control the sizes of these types with the same sort // of enum-variant manipulation tricks. -#![feature(start)] +#![no_std] -#[start] -fn start(_: isize, _: *const *const u8) -> isize { +pub fn main() -> isize { let _byte: u8 = 0; let _word: usize = 0; let _tuple: (u8, usize)= (0, 0); diff --git a/tests/ui/privacy/privacy1.rs b/tests/ui/privacy/privacy1.rs index 31f39601003..9436441ecc6 100644 --- a/tests/ui/privacy/privacy1.rs +++ b/tests/ui/privacy/privacy1.rs @@ -1,4 +1,4 @@ -#![feature(lang_items, start, no_core)] +#![feature(lang_items, no_core)] #![no_core] // makes debugging this test *a lot* easier (during resolve) #[lang="sized"] @@ -173,4 +173,4 @@ pub mod mytest { } } -#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 } +fn main() {} diff --git a/tests/ui/privacy/privacy2.rs b/tests/ui/privacy/privacy2.rs index 33292a65c5d..ab6d805544e 100644 --- a/tests/ui/privacy/privacy2.rs +++ b/tests/ui/privacy/privacy2.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes -#![feature(start, no_core)] +#![feature(no_core)] #![no_core] // makes debugging this test *a lot* easier (during resolve) // Test to make sure that globs don't leak in regular `use` statements. @@ -26,4 +26,4 @@ fn test2() { //~^ ERROR `foo` is private } -#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 } +fn main() {} diff --git a/tests/ui/privacy/privacy3.rs b/tests/ui/privacy/privacy3.rs index fb1f432410d..6298a6bc8cf 100644 --- a/tests/ui/privacy/privacy3.rs +++ b/tests/ui/privacy/privacy3.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Zdeduplicate-diagnostics=yes -#![feature(start, no_core)] +#![feature( no_core)] #![no_core] // makes debugging this test *a lot* easier (during resolve) // Test to make sure that private items imported through globs remain private @@ -26,4 +26,4 @@ fn test1() { gpriv(); } -#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 } +fn main() {} diff --git a/tests/ui/privacy/privacy4.rs b/tests/ui/privacy/privacy4.rs index fa257b80039..7341c7752bb 100644 --- a/tests/ui/privacy/privacy4.rs +++ b/tests/ui/privacy/privacy4.rs @@ -1,4 +1,4 @@ -#![feature(lang_items, start, no_core)] +#![feature(lang_items, no_core)] #![no_core] // makes debugging this test *a lot* easier (during resolve) #[lang = "sized"] pub trait Sized {} @@ -22,4 +22,4 @@ fn test2() { gpriv(); } -#[start] fn main(_: isize, _: *const *const u8) -> isize { 3 } +fn main() {} diff --git a/tests/ui/privacy/private-struct-field-ctor.stderr b/tests/ui/privacy/private-struct-field-ctor.stderr index 2a35537237a..8eb1bf7990b 100644 --- a/tests/ui/privacy/private-struct-field-ctor.stderr +++ b/tests/ui/privacy/private-struct-field-ctor.stderr @@ -2,7 +2,7 @@ error[E0451]: field `x` of struct `Foo` is private --> $DIR/private-struct-field-ctor.rs:8:22 | LL | let s = a::Foo { x: 1 }; - | ^^^^ private field + | ^ private field error: aborting due to 1 previous error diff --git a/tests/ui/privacy/private-struct-field-pattern.stderr b/tests/ui/privacy/private-struct-field-pattern.stderr index de24d1e0962..5609596721d 100644 --- a/tests/ui/privacy/private-struct-field-pattern.stderr +++ b/tests/ui/privacy/private-struct-field-pattern.stderr @@ -2,7 +2,7 @@ error[E0451]: field `x` of struct `Foo` is private --> $DIR/private-struct-field-pattern.rs:15:15 | LL | Foo { x: _ } => {} - | ^^^^ private field + | ^ private field error: aborting due to 1 previous error diff --git a/tests/ui/privacy/restricted/struct-literal-field.stderr b/tests/ui/privacy/restricted/struct-literal-field.stderr index dcdadf1da4b..e1cf7c2fadb 100644 --- a/tests/ui/privacy/restricted/struct-literal-field.stderr +++ b/tests/ui/privacy/restricted/struct-literal-field.stderr @@ -2,7 +2,7 @@ error[E0451]: field `x` of struct `S` is private --> $DIR/struct-literal-field.rs:18:9 | LL | S { x: 0 }; - | ^^^^ private field + | ^ private field error: aborting due to 1 previous error diff --git a/tests/ui/privacy/union-field-privacy-1.stderr b/tests/ui/privacy/union-field-privacy-1.stderr index b1f0b785ea7..6f883b16d02 100644 --- a/tests/ui/privacy/union-field-privacy-1.stderr +++ b/tests/ui/privacy/union-field-privacy-1.stderr @@ -2,7 +2,7 @@ error[E0451]: field `c` of union `U` is private --> $DIR/union-field-privacy-1.rs:12:20 | LL | let u = m::U { c: 0 }; - | ^^^^ private field + | ^ private field error[E0451]: field `c` of union `U` is private --> $DIR/union-field-privacy-1.rs:16:16 diff --git a/tests/ui/proc-macro/inner-attr-non-inline-mod.rs b/tests/ui/proc-macro/inner-attr-non-inline-mod.rs index 714463b6225..d4336a7f3e1 100644 --- a/tests/ui/proc-macro/inner-attr-non-inline-mod.rs +++ b/tests/ui/proc-macro/inner-attr-non-inline-mod.rs @@ -1,7 +1,6 @@ //@ compile-flags: -Z span-debug //@ error-pattern:custom inner attributes are unstable //@ error-pattern:inner macro attributes are unstable -//@ error-pattern:this was previously accepted //@ proc-macro: test-macros.rs #![no_std] // Don't load unnecessary hygiene information from std diff --git a/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr b/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr index ccc967aaff9..025eec24818 100644 --- a/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr +++ b/tests/ui/proc-macro/inner-attr-non-inline-mod.stderr @@ -1,3 +1,13 @@ +error[E0658]: custom inner attributes are unstable + --> $DIR/module_with_attrs.rs:3:4 + | +LL | #![rustfmt::skip] + | ^^^^^^^^^^^^^ + | + = note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information + = help: add `#![feature(custom_inner_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[E0658]: inner macro attributes are unstable --> $DIR/module_with_attrs.rs:4:4 | @@ -9,7 +19,7 @@ LL | #![print_attr] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: non-inline modules in proc macro input are unstable - --> $DIR/inner-attr-non-inline-mod.rs:14:1 + --> $DIR/inner-attr-non-inline-mod.rs:13:1 | LL | mod module_with_attrs; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -19,7 +29,7 @@ LL | mod module_with_attrs; = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: custom inner attributes are unstable - --> $DIR/inner-attr-non-inline-mod.rs:14:1 + --> $DIR/inner-attr-non-inline-mod.rs:13:1 | LL | mod module_with_attrs; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -28,27 +38,6 @@ LL | mod module_with_attrs; = help: add `#![feature(custom_inner_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: custom inner attributes are unstable - --> $DIR/module_with_attrs.rs:3:4 - | -LL | #![rustfmt::skip] - | ^^^^^^^^^^^^^ - | - = 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 #64266 <https://github.com/rust-lang/rust/issues/64266> - = note: `#[deny(soft_unstable)]` on by default - error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. -Future incompatibility report: Future breakage diagnostic: -error: custom inner attributes are unstable - --> $DIR/module_with_attrs.rs:3:4 - | -LL | #![rustfmt::skip] - | ^^^^^^^^^^^^^ - | - = 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 #64266 <https://github.com/rust-lang/rust/issues/64266> - = note: `#[deny(soft_unstable)]` on by default - diff --git a/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout b/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout index aaec40669e6..450542f68c6 100644 --- a/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout +++ b/tests/ui/proc-macro/inner-attr-non-inline-mod.stdout @@ -4,35 +4,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "deny", - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "unused_attributes", - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, ], - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, ], - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Ident { ident: "mod", - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Ident { ident: "module_with_attrs", - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Group { delimiter: Brace, @@ -40,38 +40,38 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "rustfmt", - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Punct { ch: ':', spacing: Joint, - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, Ident { ident: "skip", - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, ], - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, ], - span: $DIR/inner-attr-non-inline-mod.rs:14:1: 14:23 (#0), + span: $DIR/inner-attr-non-inline-mod.rs:13:1: 13:23 (#0), }, ] diff --git a/tests/ui/proc-macro/proc-macro-gates.rs b/tests/ui/proc-macro/proc-macro-gates.rs index bf384bc479b..04e097eb2f7 100644 --- a/tests/ui/proc-macro/proc-macro-gates.rs +++ b/tests/ui/proc-macro/proc-macro-gates.rs @@ -47,7 +47,6 @@ fn attrs() { fn test_case() { #![test] //~ ERROR inner macro attributes are unstable - //~| WARN this was previously accepted } fn main() {} diff --git a/tests/ui/proc-macro/proc-macro-gates.stderr b/tests/ui/proc-macro/proc-macro-gates.stderr index a05a7d0b185..3607b062a5f 100644 --- a/tests/ui/proc-macro/proc-macro-gates.stderr +++ b/tests/ui/proc-macro/proc-macro-gates.stderr @@ -84,27 +84,16 @@ LL | let _x = #[identity_attr] println!(); = help: add `#![feature(proc_macro_hygiene)]` 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: inner macro attributes are unstable +error[E0658]: inner macro attributes are unstable --> $DIR/proc-macro-gates.rs:49:8 | LL | #![test] | ^^^^ | - = 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 #64266 <https://github.com/rust-lang/rust/issues/64266> - = note: `#[deny(soft_unstable)]` on by default + = note: see issue #54726 <https://github.com/rust-lang/rust/issues/54726> for more information + = help: add `#![feature(custom_inner_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 10 previous errors For more information about this error, try `rustc --explain E0658`. -Future incompatibility report: Future breakage diagnostic: -error: inner macro attributes are unstable - --> $DIR/proc-macro-gates.rs:49:8 - | -LL | #![test] - | ^^^^ - | - = 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 #64266 <https://github.com/rust-lang/rust/issues/64266> - = note: `#[deny(soft_unstable)]` on by default - diff --git a/tests/ui/resolve/auxiliary/fake_matches.rs b/tests/ui/resolve/auxiliary/fake_matches.rs new file mode 100644 index 00000000000..6d42972cbac --- /dev/null +++ b/tests/ui/resolve/auxiliary/fake_matches.rs @@ -0,0 +1,13 @@ +// Helper for test tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs + +//@ edition: 2018 + +#[macro_export] +macro_rules! assert_matches { + ( $e:expr , $($pat:pat)|+ ) => { + match $e { + $($pat)|+ => (), + _ => (), + } + }; +} diff --git a/tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs b/tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs new file mode 100644 index 00000000000..8267a9250ec --- /dev/null +++ b/tests/ui/resolve/const-with-typo-in-pattern-binding-ice-135289.rs @@ -0,0 +1,17 @@ +// This is a non-regression test for issue 135289, where the "const with typo in pattern" diagnostic +// caused an ICE when unexpectedly pretty printing a type for unreachable arms via a macro defined +// in a dependency. + +#![warn(unreachable_patterns)] // needed to reproduce the ICE described in #135289 + +//@ check-pass +//@ aux-build: fake_matches.rs +extern crate fake_matches; + +const _A: u64 = 0; +pub fn f() -> u64 { + 0 +} +fn main() { + fake_matches::assert_matches!(f(), _non_existent); +} diff --git a/tests/ui/resolve/issue-3907-2.stderr b/tests/ui/resolve/issue-3907-2.stderr index 7c47c5973e3..4ab72a42eb8 100644 --- a/tests/ui/resolve/issue-3907-2.stderr +++ b/tests/ui/resolve/issue-3907-2.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `issue_3907::Foo` cannot be made into an object +error[E0038]: the trait `issue_3907::Foo` is not dyn compatible --> $DIR/issue-3907-2.rs:11:12 | LL | fn bar(_x: Foo) {} - | ^^^ `issue_3907::Foo` cannot be made into an object + | ^^^ `issue_3907::Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/auxiliary/issue-3907.rs:2:8 | LL | fn bar(); - | ^^^ the trait cannot be made into an object because associated function `bar` has no `self` parameter + | ^^^ the trait is not dyn compatible because associated function `bar` has no `self` parameter error[E0277]: the size for values of type `(dyn issue_3907::Foo + 'static)` cannot be known at compilation time --> $DIR/issue-3907-2.rs:11:12 diff --git a/tests/ui/resolve/multiple_definitions_attribute_merging.stderr b/tests/ui/resolve/multiple_definitions_attribute_merging.stderr index 804fa079bb9..ac6307c7a69 100644 --- a/tests/ui/resolve/multiple_definitions_attribute_merging.stderr +++ b/tests/ui/resolve/multiple_definitions_attribute_merging.stderr @@ -21,7 +21,7 @@ Box<dyn Any> query stack during panic: #0 [mir_built] building MIR for `<impl at $DIR/multiple_definitions_attribute_merging.rs:15:10: 15:19>::eq` #1 [check_unsafety] unsafety-checking `<impl at $DIR/multiple_definitions_attribute_merging.rs:15:10: 15:19>::eq` -end of query stack +... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0428`. diff --git a/tests/ui/resolve/proc_macro_generated_packed.stderr b/tests/ui/resolve/proc_macro_generated_packed.stderr index a5a02c9c393..8b700595034 100644 --- a/tests/ui/resolve/proc_macro_generated_packed.stderr +++ b/tests/ui/resolve/proc_macro_generated_packed.stderr @@ -12,6 +12,6 @@ Box<dyn Any> query stack during panic: #0 [mir_built] building MIR for `<impl at $DIR/proc_macro_generated_packed.rs:15:10: 15:19>::eq` #1 [check_unsafety] unsafety-checking `<impl at $DIR/proc_macro_generated_packed.rs:15:10: 15:19>::eq` -end of query stack +... and 1 other queries... use `env RUST_BACKTRACE=1` to see the full query stack error: aborting due to 1 previous error diff --git a/tests/ui/resolve/resolve-issue-135614-assoc-const.import_trait_associated_functions.stderr b/tests/ui/resolve/resolve-issue-135614-assoc-const.import_trait_associated_functions.stderr new file mode 100644 index 00000000000..b41fa1818e2 --- /dev/null +++ b/tests/ui/resolve/resolve-issue-135614-assoc-const.import_trait_associated_functions.stderr @@ -0,0 +1,19 @@ +error[E0005]: refutable pattern in local binding + --> $DIR/resolve-issue-135614-assoc-const.rs:21:9 + | +LL | let DEFAULT: u32 = 0; + | ^^^^^^^ pattern `1_u32..=u32::MAX` not covered +LL | const DEFAULT: u32 = 0; + | ------------------ missing patterns are not covered because `DEFAULT` is interpreted as a constant pattern, not a new variable + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html + = note: the matched value is of type `u32` +help: introduce a variable instead + | +LL | let DEFAULT_var: u32 = 0; + | ~~~~~~~~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0005`. diff --git a/tests/ui/resolve/resolve-issue-135614-assoc-const.normal.stderr b/tests/ui/resolve/resolve-issue-135614-assoc-const.normal.stderr new file mode 100644 index 00000000000..908f5bdd897 --- /dev/null +++ b/tests/ui/resolve/resolve-issue-135614-assoc-const.normal.stderr @@ -0,0 +1,30 @@ +error[E0658]: `use` associated items of traits is unstable + --> $DIR/resolve-issue-135614-assoc-const.rs:6:5 + | +LL | use MyDefault::DEFAULT; + | ^^^^^^^^^^^^^^^^^^ + | + = note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information + = help: add `#![feature(import_trait_associated_functions)]` 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[E0005]: refutable pattern in local binding + --> $DIR/resolve-issue-135614-assoc-const.rs:21:9 + | +LL | let DEFAULT: u32 = 0; + | ^^^^^^^ pattern `1_u32..=u32::MAX` not covered +LL | const DEFAULT: u32 = 0; + | ------------------ missing patterns are not covered because `DEFAULT` is interpreted as a constant pattern, not a new variable + | + = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant + = note: for more information, visit https://doc.rust-lang.org/book/ch19-02-refutability.html + = note: the matched value is of type `u32` +help: introduce a variable instead + | +LL | let DEFAULT_var: u32 = 0; + | ~~~~~~~~~~~ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0005, E0658. +For more information about an error, try `rustc --explain E0005`. diff --git a/tests/ui/resolve/resolve-issue-135614-assoc-const.rs b/tests/ui/resolve/resolve-issue-135614-assoc-const.rs new file mode 100644 index 00000000000..5a592922cd4 --- /dev/null +++ b/tests/ui/resolve/resolve-issue-135614-assoc-const.rs @@ -0,0 +1,30 @@ +//@ revisions: normal import_trait_associated_functions +#![cfg_attr(import_trait_associated_functions, feature(import_trait_associated_functions))] + +// Makes sure that imported constant can be used in pattern bindings. + +use MyDefault::DEFAULT; //[normal]~ ERROR `use` associated items of traits is unstable + +trait MyDefault { + const DEFAULT: Self; +} + +impl MyDefault for u32 { + const DEFAULT: u32 = 0; +} + +impl MyDefault for () { + const DEFAULT: () = (); +} + +fn foo(x: u32) -> u32 { + let DEFAULT: u32 = 0; //~ ERROR refutable pattern in local binding + const DEFAULT: u32 = 0; + if let DEFAULT = x { DEFAULT } else { 1 } +} + +fn bar() { + let DEFAULT = (); +} + +fn main() {} diff --git a/tests/ui/resolve/resolve-issue-135614.normal.stderr b/tests/ui/resolve/resolve-issue-135614.normal.stderr new file mode 100644 index 00000000000..a9adeb0848e --- /dev/null +++ b/tests/ui/resolve/resolve-issue-135614.normal.stderr @@ -0,0 +1,13 @@ +error[E0658]: `use` associated items of traits is unstable + --> $DIR/resolve-issue-135614.rs:7:5 + | +LL | use A::b; + | ^^^^ + | + = note: see issue #134691 <https://github.com/rust-lang/rust/issues/134691> for more information + = help: add `#![feature(import_trait_associated_functions)]` 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/resolve/resolve-issue-135614.rs b/tests/ui/resolve/resolve-issue-135614.rs new file mode 100644 index 00000000000..fec9499365b --- /dev/null +++ b/tests/ui/resolve/resolve-issue-135614.rs @@ -0,0 +1,15 @@ +//@ revisions: normal import_trait_associated_functions +//@[import_trait_associated_functions] check-pass +#![cfg_attr(import_trait_associated_functions, feature(import_trait_associated_functions))] + +// Makes sure that imported associated functions are shadowed by the local declarations. + +use A::b; //[normal]~ ERROR `use` associated items of traits is unstable + +trait A { + fn b() {} +} + +fn main() { + let b: (); +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs new file mode 100644 index 00000000000..2a7e730af16 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.rs @@ -0,0 +1,12 @@ +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum E { A } + +fn main() { + match E::A { + ! | //~ ERROR: a trailing `|` is not allowed in an or-pattern + //~^ ERROR: mismatched types + if true => {} //~ ERROR: a never pattern is always unreachable + } +} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr new file mode 100644 index 00000000000..26731e29ffc --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-130779-never-arm-no-oatherwise-block.stderr @@ -0,0 +1,33 @@ +error: a trailing `|` is not allowed in an or-pattern + --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:8:11 + | +LL | ! | + | - ^ + | | + | while parsing this or-pattern starting here + | +help: remove the `|` + | +LL - ! | +LL + ! + | + +error: a never pattern is always unreachable + --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:10:20 + | +LL | if true => {} + | ^^ + | | + | this will never be executed + | help: remove this expression + +error: mismatched types + --> $DIR/ICE-130779-never-arm-no-oatherwise-block.rs:8:9 + | +LL | ! | + | ^ a never pattern must be used on an uninhabited type + | + = note: the matched value is of type `E` + +error: aborting due to 3 previous errors + diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs new file mode 100644 index 00000000000..4f52f6ee4bd --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.rs @@ -0,0 +1,16 @@ +#![feature(never_type)] +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +fn foo(x: Void) { + loop { + match x { + (!|!) if false => {} //~ ERROR a never pattern is always unreachable + _ => {} + } + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr new file mode 100644 index 00000000000..cc451fed318 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133063-never-arm-no-otherwise-block.stderr @@ -0,0 +1,11 @@ +error: a never pattern is always unreachable + --> $DIR/ICE-133063-never-arm-no-otherwise-block.rs:10:31 + | +LL | (!|!) if false => {} + | ^^ + | | + | this will never be executed + | help: remove this expression + +error: aborting due to 1 previous error + diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs new file mode 100644 index 00000000000..bca2ab56570 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.rs @@ -0,0 +1,14 @@ +#![feature(never_type)] +#![feature(never_patterns)] +#![allow(incomplete_features)] + +enum Void {} + +fn foo(x: Void) { + match x { + (!|!) if true => {} //~ ERROR a never pattern is always unreachable + (!|!) if true => {} //~ ERROR a never pattern is always unreachable + } +} + +fn main() {} diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr new file mode 100644 index 00000000000..5da9642dc19 --- /dev/null +++ b/tests/ui/rfcs/rfc-0000-never_patterns/ICE-133117-duplicate-never-arm.stderr @@ -0,0 +1,20 @@ +error: a never pattern is always unreachable + --> $DIR/ICE-133117-duplicate-never-arm.rs:9:26 + | +LL | (!|!) if true => {} + | ^^ + | | + | this will never be executed + | help: remove this expression + +error: a never pattern is always unreachable + --> $DIR/ICE-133117-duplicate-never-arm.rs:10:26 + | +LL | (!|!) if true => {} + | ^^ + | | + | this will never be executed + | help: remove this expression + +error: aborting due to 2 previous errors + diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs deleted file mode 100644 index f0e111b578f..00000000000 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(start)] - -#[start] -#[track_caller] //~ ERROR `#[start]` function is not allowed to be `#[track_caller]` -fn start(_argc: isize, _argv: *const *const u8) -> isize { - panic!("{}: oh no", std::panic::Location::caller()); -} diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr deleted file mode 100644 index 2738444f21f..00000000000 --- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-start.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: `#[start]` function is not allowed to be `#[track_caller]` - --> $DIR/error-with-start.rs:4:1 - | -LL | #[track_caller] - | ^^^^^^^^^^^^^^^ -LL | fn start(_argc: isize, _argv: *const *const u8) -> isize { - | -------------------------------------------------------- `#[start]` function is not allowed to be `#[track_caller]` - -error: aborting due to 1 previous error - diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs deleted file mode 100644 index 6aa8f6fd821..00000000000 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ only-x86_64 - -#![feature(start)] -#![feature(target_feature_11)] - -#[start] -#[target_feature(enable = "avx2")] -//~^ ERROR `#[start]` function is not allowed to have `#[target_feature]` -fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 } diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr deleted file mode 100644 index d0a67c4f6a8..00000000000 --- a/tests/ui/rfcs/rfc-2396-target_feature-11/issue-108645-target-feature-on-start.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error: `#[start]` function is not allowed to have `#[target_feature]` - --> $DIR/issue-108645-target-feature-on-start.rs:7:1 - | -LL | #[target_feature(enable = "avx2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 } - | -------------------------------------------------------- `#[start]` function is not allowed to have `#[target_feature]` - -error: aborting due to 1 previous error - diff --git a/tests/ui/runtime/native-print-no-runtime.rs b/tests/ui/runtime/native-print-no-runtime.rs deleted file mode 100644 index f0ed7d97b2c..00000000000 --- a/tests/ui/runtime/native-print-no-runtime.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -#![feature(start)] - -#[start] -pub fn main(_: isize, _: *const *const u8) -> isize { - println!("hello"); - 0 -} diff --git a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs index 229408fb724..f3f9ce0bd87 100644 --- a/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs +++ b/tests/ui/runtime/on-broken-pipe/auxiliary/assert-sigpipe-disposition.rs @@ -4,15 +4,16 @@ //@ compile-flags: -Cpanic=abort //@ no-prefer-dynamic so panic=abort works -#![feature(start, rustc_private)] +#![feature(rustc_private)] +#![no_main] extern crate libc; -// Use #[start] so we don't have a runtime that messes with SIGPIPE. -#[start] -fn start(argc: isize, argv: *const *const u8) -> isize { +// Use no_main so we don't have a runtime that messes with SIGPIPE. +#[no_mangle] +extern "C" fn main(argc: core::ffi::c_int, argv: *const *const u8) -> core::ffi::c_int { assert_eq!(argc, 2, "Must pass SIG_IGN or SIG_DFL as first arg"); - let arg1 = unsafe { std::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) } + let arg1 = unsafe { core::ffi::CStr::from_ptr(*argv.offset(1) as *const libc::c_char) } .to_str() .unwrap(); @@ -23,8 +24,8 @@ fn start(argc: isize, argv: *const *const u8) -> isize { }; let actual = unsafe { - let mut actual: libc::sigaction = std::mem::zeroed(); - libc::sigaction(libc::SIGPIPE, std::ptr::null(), &mut actual); + let mut actual: libc::sigaction = core::mem::zeroed(); + libc::sigaction(libc::SIGPIPE, core::ptr::null(), &mut actual); #[cfg(not(target_os = "aix"))] { actual.sa_sigaction diff --git a/tests/ui/runtime/running-with-no-runtime.rs b/tests/ui/runtime/running-with-no-runtime.rs index 695025b3859..5c219b6feda 100644 --- a/tests/ui/runtime/running-with-no-runtime.rs +++ b/tests/ui/runtime/running-with-no-runtime.rs @@ -2,15 +2,15 @@ //@ ignore-wasm32 spawning processes is not supported //@ ignore-sgx no processes -#![feature(start)] +#![no_main] use std::ffi::CStr; use std::process::{Command, Output}; use std::panic; use std::str; -#[start] -fn start(argc: isize, argv: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(argc: core::ffi::c_int, argv: *const *const u8) -> core::ffi::c_int { if argc > 1 { unsafe { match **argv.offset(1) as char { diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed index 8b179f7ef93..cba3d7f1f9f 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.fixed @@ -40,6 +40,15 @@ macro_rules! meta2 { } } +macro_rules! with_cfg_attr { + () => { + #[cfg_attr(all(), unsafe(link_section = ".custom_section"))] + //~^ ERROR: unsafe attribute used without unsafe + //~| WARN this is accepted in the current edition + pub extern "C" fn abc() {} + }; +} + tt!([unsafe(no_mangle)]); //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition @@ -52,6 +61,8 @@ meta2!(unsafe(export_name = "baw")); //~| WARN this is accepted in the current edition ident2!(export_name, "bars"); +with_cfg_attr!(); + #[unsafe(no_mangle)] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs index 34e5a6b96e3..4bbf9b25de5 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.rs @@ -40,6 +40,15 @@ macro_rules! meta2 { } } +macro_rules! with_cfg_attr { + () => { + #[cfg_attr(all(), link_section = ".custom_section")] + //~^ ERROR: unsafe attribute used without unsafe + //~| WARN this is accepted in the current edition + pub extern "C" fn abc() {} + }; +} + tt!([no_mangle]); //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition @@ -52,6 +61,8 @@ meta2!(export_name = "baw"); //~| WARN this is accepted in the current edition ident2!(export_name, "bars"); +with_cfg_attr!(); + #[no_mangle] //~^ ERROR: unsafe attribute used without unsafe //~| WARN this is accepted in the current edition diff --git a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr index 87330d2693d..15a48fb7159 100644 --- a/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr +++ b/tests/ui/rust-2024/unsafe-attributes/unsafe-attributes-fix.stderr @@ -1,5 +1,5 @@ error: unsafe attribute used without unsafe - --> $DIR/unsafe-attributes-fix.rs:43:6 + --> $DIR/unsafe-attributes-fix.rs:52:6 | LL | tt!([no_mangle]); | ^^^^^^^^^ usage of unsafe attribute @@ -34,7 +34,7 @@ LL | #[unsafe($e)] | +++++++ + error: unsafe attribute used without unsafe - --> $DIR/unsafe-attributes-fix.rs:47:7 + --> $DIR/unsafe-attributes-fix.rs:56:7 | LL | meta!(no_mangle); | ^^^^^^^^^ usage of unsafe attribute @@ -47,7 +47,7 @@ LL | meta!(unsafe(no_mangle)); | +++++++ + error: unsafe attribute used without unsafe - --> $DIR/unsafe-attributes-fix.rs:50:8 + --> $DIR/unsafe-attributes-fix.rs:59:8 | LL | meta2!(export_name = "baw"); | ^^^^^^^^^^^ usage of unsafe attribute @@ -77,7 +77,24 @@ LL | #[unsafe($e = $l)] | +++++++ + error: unsafe attribute used without unsafe - --> $DIR/unsafe-attributes-fix.rs:55:3 + --> $DIR/unsafe-attributes-fix.rs:45:27 + | +LL | #[cfg_attr(all(), link_section = ".custom_section")] + | ^^^^^^^^^^^^ usage of unsafe attribute +... +LL | with_cfg_attr!(); + | ---------------- in this macro invocation + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024! + = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-attributes.html> + = note: this error originates in the macro `with_cfg_attr` (in Nightly builds, run with -Z macro-backtrace for more info) +help: wrap the attribute in `unsafe(...)` + | +LL | #[cfg_attr(all(), unsafe(link_section = ".custom_section"))] + | +++++++ + + +error: unsafe attribute used without unsafe + --> $DIR/unsafe-attributes-fix.rs:66:3 | LL | #[no_mangle] | ^^^^^^^^^ usage of unsafe attribute @@ -89,5 +106,5 @@ help: wrap the attribute in `unsafe(...)` LL | #[unsafe(no_mangle)] | +++++++ + -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/sanitizer/memory-eager.rs b/tests/ui/sanitizer/memory-eager.rs index 9e7889fa1bc..532d7b308f6 100644 --- a/tests/ui/sanitizer/memory-eager.rs +++ b/tests/ui/sanitizer/memory-eager.rs @@ -15,7 +15,7 @@ // since it will be linked with an uninstrumented version of it. #![feature(core_intrinsics)] -#![feature(start)] +#![no_main] use std::hint::black_box; use std::mem::MaybeUninit; @@ -29,8 +29,8 @@ fn random() -> char { black_box(r) } -#[start] -fn main(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: std::ffi::c_int, _argv: *const *const u8) -> std::ffi::c_int { random(); 0 } diff --git a/tests/ui/sanitizer/memory-passing.rs b/tests/ui/sanitizer/memory-passing.rs index c8ab64bfaf8..96a4cd909c7 100644 --- a/tests/ui/sanitizer/memory-passing.rs +++ b/tests/ui/sanitizer/memory-passing.rs @@ -12,8 +12,8 @@ // since it will be linked with an uninstrumented version of it. #![feature(core_intrinsics)] -#![feature(start)] #![allow(invalid_value)] +#![no_main] use std::hint::black_box; @@ -25,8 +25,8 @@ fn calling_black_box_on_zst_ok() { black_box(zst); } -#[start] -fn main(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: std::ffi::c_int, _argv: *const *const u8) -> std::ffi::c_int { calling_black_box_on_zst_ok(); 0 } diff --git a/tests/ui/sanitizer/memory.rs b/tests/ui/sanitizer/memory.rs index bd2d6771749..a91fefe4d16 100644 --- a/tests/ui/sanitizer/memory.rs +++ b/tests/ui/sanitizer/memory.rs @@ -15,8 +15,8 @@ // since it will be linked with an uninstrumented version of it. #![feature(core_intrinsics)] -#![feature(start)] #![allow(invalid_value)] +#![no_main] use std::hint::black_box; use std::mem::MaybeUninit; @@ -39,8 +39,8 @@ fn xor(a: &[isize]) -> isize { s } -#[start] -fn main(_: isize, _: *const *const u8) -> isize { +#[no_mangle] +extern "C" fn main(_argc: std::ffi::c_int, _argv: *const *const u8) -> std::ffi::c_int { let r = black_box(random as fn() -> [isize; 32])(); - xor(&r) + xor(&r) as std::ffi::c_int } diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr index 2eb7597d5c1..3e018995ba5 100644 --- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.curr.stderr @@ -1,38 +1,40 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:32 | LL | fn foo(self: &Rc<Self>) -> usize; | --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self` ... LL | let x = Rc::new(5usize) as Rc<dyn Foo>; - | ^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn foo(self: &Rc<Self>) -> usize; | ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on - = help: only type `usize` implements the trait, consider using it directly instead + = help: only type `usize` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:13 | LL | fn foo(self: &Rc<Self>) -> usize; | --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self` ... LL | let x = Rc::new(5usize) as Rc<dyn Foo>; - | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn foo(self: &Rc<Self>) -> usize; | ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on - = help: only type `usize` implements the trait, consider using it directly instead + = help: only type `usize` implements `Foo`; consider using it directly instead. = note: required for the cast from `Rc<usize>` to `Rc<dyn Foo>` error: aborting due to 2 previous errors diff --git a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr index 02af692c4a3..12c93d58537 100644 --- a/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr +++ b/tests/ui/self/arbitrary-self-types-dyn-incompatible.dyn_compatible_for_dispatch.stderr @@ -1,20 +1,21 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/arbitrary-self-types-dyn-incompatible.rs:33:13 | LL | fn foo(self: &Rc<Self>) -> usize; | --------- help: consider changing method `foo`'s `self` parameter to be `&self`: `&Self` ... LL | let x = Rc::new(5usize) as Rc<dyn Foo>; - | ^^^^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/arbitrary-self-types-dyn-incompatible.rs:8:18 | LL | trait Foo { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn foo(self: &Rc<Self>) -> usize; | ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on - = help: only type `usize` implements the trait, consider using it directly instead + = help: only type `usize` implements `Foo`; consider using it directly instead. = note: required for the cast from `Rc<usize>` to `Rc<dyn Foo>` error: aborting due to 1 previous error diff --git a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr index 0a5f58288fa..0f2006e932b 100644 --- a/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr +++ b/tests/ui/stability-attribute/const-stability-attribute-implies-no-feature.stderr @@ -4,7 +4,10 @@ error: `foobar` is not yet stable as a const fn LL | foobar(); | ^^^^^^^^ | - = help: add `#![feature(const_foobar)]` to the crate attributes to enable +help: add `#![feature(const_foobar)]` to the crate attributes to enable + | +LL + #![feature(const_foobar)] + | error: aborting due to 1 previous error diff --git a/tests/ui/stable-mir-print/operands.stdout b/tests/ui/stable-mir-print/operands.stdout index c3b1151ae24..3c27878b3cf 100644 --- a/tests/ui/stable-mir-print/operands.stdout +++ b/tests/ui/stable-mir-print/operands.stdout @@ -5,183 +5,187 @@ fn operands(_1: u8) -> () { let _2: [u8; 10]; let _3: u8; let _4: usize; - let mut _5: bool; - let _6: u8; - let _7: usize; - let mut _8: (usize, bool); - let mut _9: bool; - let mut _10: (&u8, &u8); - let mut _11: &u8; - let mut _12: &u8; - let _13: &u8; - let _14: &u8; - let mut _15: bool; - let mut _16: u8; - let mut _17: u8; - let _18: core::panicking::AssertKind; - let _19: !; - let mut _20: Option<Arguments<'_>>; - let _21: &u8; - let _22: u8; - let mut _23: (&u8, &u8); - let mut _24: &u8; - let mut _25: &u8; - let _26: &u8; - let _27: &u8; - let mut _28: bool; - let mut _29: u8; - let mut _30: u8; - let _31: core::panicking::AssertKind; - let _32: !; - let mut _33: Option<Arguments<'_>>; - let _34: (u8, u8); - let _35: u8; - let _36: u8; - let mut _37: (&u8, &u8); - let mut _38: &u8; - let mut _39: &u8; - let _40: &u8; - let _41: &u8; - let mut _42: bool; - let mut _43: u8; - let mut _44: u8; - let _45: core::panicking::AssertKind; - let _46: !; - let mut _47: Option<Arguments<'_>>; - let _48: usize; - let mut _49: &[u8]; - let mut _50: &[u8; 10]; - let _51: usize; - let _52: &usize; - let mut _53: (&usize, &usize); - let mut _54: &usize; - let mut _55: &usize; - let _56: &usize; - let _57: &usize; - let mut _58: bool; - let mut _59: usize; - let mut _60: usize; - let _61: core::panicking::AssertKind; - let _62: !; - let mut _63: Option<Arguments<'_>>; + let mut _5: usize; + let mut _6: bool; + let _7: u8; + let _8: usize; + let mut _9: (usize, bool); + let mut _10: usize; + let mut _11: bool; + let mut _12: (&u8, &u8); + let mut _13: &u8; + let mut _14: &u8; + let _15: &u8; + let _16: &u8; + let mut _17: bool; + let mut _18: u8; + let mut _19: u8; + let _20: core::panicking::AssertKind; + let _21: !; + let mut _22: Option<Arguments<'_>>; + let _23: &u8; + let _24: u8; + let mut _25: (&u8, &u8); + let mut _26: &u8; + let mut _27: &u8; + let _28: &u8; + let _29: &u8; + let mut _30: bool; + let mut _31: u8; + let mut _32: u8; + let _33: core::panicking::AssertKind; + let _34: !; + let mut _35: Option<Arguments<'_>>; + let _36: (u8, u8); + let _37: u8; + let _38: u8; + let mut _39: (&u8, &u8); + let mut _40: &u8; + let mut _41: &u8; + let _42: &u8; + let _43: &u8; + let mut _44: bool; + let mut _45: u8; + let mut _46: u8; + let _47: core::panicking::AssertKind; + let _48: !; + let mut _49: Option<Arguments<'_>>; + let _50: usize; + let mut _51: &[u8]; + let mut _52: &[u8; 10]; + let _53: usize; + let _54: &usize; + let mut _55: (&usize, &usize); + let mut _56: &usize; + let mut _57: &usize; + let _58: &usize; + let _59: &usize; + let mut _60: bool; + let mut _61: usize; + let mut _62: usize; + let _63: core::panicking::AssertKind; + let _64: !; + let mut _65: Option<Arguments<'_>>; debug val => _1; debug array => _2; debug first => _3; - debug last => _6; - debug left_val => _13; - debug right_val => _14; - debug kind => _18; - debug reference => _21; - debug dereferenced => _22; - debug left_val => _26; - debug right_val => _27; - debug kind => _31; - debug tuple => _34; - debug first_again => _35; - debug first_again_again => _36; - debug left_val => _40; - debug right_val => _41; - debug kind => _45; - debug length => _48; - debug size_of => _51; - debug left_val => _56; - debug right_val => _57; - debug kind => _61; + debug last => _7; + debug left_val => _15; + debug right_val => _16; + debug kind => _20; + debug reference => _23; + debug dereferenced => _24; + debug left_val => _28; + debug right_val => _29; + debug kind => _33; + debug tuple => _36; + debug first_again => _37; + debug first_again_again => _38; + debug left_val => _42; + debug right_val => _43; + debug kind => _47; + debug length => _50; + debug size_of => _53; + debug left_val => _58; + debug right_val => _59; + debug kind => _63; bb0: { _2 = [_1; 10]; _4 = 0_usize; - _5 = Lt(_4, 10_usize); - assert(move _5, "index out of bounds: the length is {} but the index is {}", 10_usize, _4) -> [success: bb1, unwind unreachable]; + _5 = 10_usize; + _6 = Lt(_4, _5); + assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind unreachable]; } bb1: { _3 = _2[_4]; - _8 = CheckedSub(10_usize, 1_usize); - assert(!move (_8.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable]; + _9 = CheckedSub(10_usize, 1_usize); + assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", 10_usize, 1_usize) -> [success: bb2, unwind unreachable]; } bb2: { - _7 = move (_8.0: usize); - _9 = Lt(_7, 10_usize); - assert(move _9, "index out of bounds: the length is {} but the index is {}", 10_usize, _7) -> [success: bb3, unwind unreachable]; + _8 = move (_9.0: usize); + _10 = 10_usize; + _11 = Lt(_8, _10); + assert(move _11, "index out of bounds: the length is {} but the index is {}", move _10, _8) -> [success: bb3, unwind unreachable]; } bb3: { - _6 = _2[_7]; - _11 = &_3; - _12 = &_6; - _10 = (move _11, move _12); - _13 = (_10.0: &u8); - _14 = (_10.1: &u8); - _16 = (*_13); - _17 = (*_14); - _15 = Eq(move _16, move _17); - switchInt(move _15) -> [0: bb5, otherwise: bb4]; + _7 = _2[_8]; + _13 = &_3; + _14 = &_7; + _12 = (move _13, move _14); + _15 = (_12.0: &u8); + _16 = (_12.1: &u8); + _18 = (*_15); + _19 = (*_16); + _17 = Eq(move _18, move _19); + switchInt(move _17) -> [0: bb5, otherwise: bb4]; } bb4: { - _21 = &_3; - _22 = (*_21); - _24 = &_22; - _25 = &_3; - _23 = (move _24, move _25); - _26 = (_23.0: &u8); - _27 = (_23.1: &u8); - _29 = (*_26); - _30 = (*_27); - _28 = Eq(move _29, move _30); - switchInt(move _28) -> [0: bb7, otherwise: bb6]; + _23 = &_3; + _24 = (*_23); + _26 = &_24; + _27 = &_3; + _25 = (move _26, move _27); + _28 = (_25.0: &u8); + _29 = (_25.1: &u8); + _31 = (*_28); + _32 = (*_29); + _30 = Eq(move _31, move _32); + switchInt(move _30) -> [0: bb7, otherwise: bb6]; } bb5: { - _18 = core::panicking::AssertKind::Eq; - _20 = std::option::Option::None; - _19 = core::panicking::assert_failed::<u8, u8>(move _18, _13, _14, move _20) -> unwind unreachable; + _20 = core::panicking::AssertKind::Eq; + _22 = std::option::Option::None; + _21 = core::panicking::assert_failed::<u8, u8>(move _20, _15, _16, move _22) -> unwind unreachable; } bb6: { - _34 = (_3, _6); - _35 = (_34.0: u8); - _36 = (_34.0: u8); - _38 = &_35; - _39 = &_36; - _37 = (move _38, move _39); - _40 = (_37.0: &u8); - _41 = (_37.1: &u8); - _43 = (*_40); - _44 = (*_41); - _42 = Eq(move _43, move _44); - switchInt(move _42) -> [0: bb9, otherwise: bb8]; + _36 = (_3, _7); + _37 = (_36.0: u8); + _38 = (_36.0: u8); + _40 = &_37; + _41 = &_38; + _39 = (move _40, move _41); + _42 = (_39.0: &u8); + _43 = (_39.1: &u8); + _45 = (*_42); + _46 = (*_43); + _44 = Eq(move _45, move _46); + switchInt(move _44) -> [0: bb9, otherwise: bb8]; } bb7: { - _31 = core::panicking::AssertKind::Eq; - _33 = std::option::Option::None; - _32 = core::panicking::assert_failed::<u8, u8>(move _31, _26, _27, move _33) -> unwind unreachable; + _33 = core::panicking::AssertKind::Eq; + _35 = std::option::Option::None; + _34 = core::panicking::assert_failed::<u8, u8>(move _33, _28, _29, move _35) -> unwind unreachable; } bb8: { - _50 = &_2; - _49 = move _50 as &[u8]; - _48 = PtrMetadata(move _49); - _52 = &_48; - _51 = std::mem::size_of_val::<usize>(_52) -> [return: bb10, unwind unreachable]; + _52 = &_2; + _51 = move _52 as &[u8]; + _50 = PtrMetadata(move _51); + _54 = &_50; + _53 = std::mem::size_of_val::<usize>(_54) -> [return: bb10, unwind unreachable]; } bb9: { - _45 = core::panicking::AssertKind::Eq; - _47 = std::option::Option::None; - _46 = core::panicking::assert_failed::<u8, u8>(move _45, _40, _41, move _47) -> unwind unreachable; + _47 = core::panicking::AssertKind::Eq; + _49 = std::option::Option::None; + _48 = core::panicking::assert_failed::<u8, u8>(move _47, _42, _43, move _49) -> unwind unreachable; } bb10: { - _54 = &_48; - _55 = &_51; - _53 = (move _54, move _55); - _56 = (_53.0: &usize); - _57 = (_53.1: &usize); - _59 = (*_56); - _60 = (*_57); - _58 = Eq(move _59, move _60); - switchInt(move _58) -> [0: bb12, otherwise: bb11]; + _56 = &_50; + _57 = &_53; + _55 = (move _56, move _57); + _58 = (_55.0: &usize); + _59 = (_55.1: &usize); + _61 = (*_58); + _62 = (*_59); + _60 = Eq(move _61, move _62); + switchInt(move _60) -> [0: bb12, otherwise: bb11]; } bb11: { return; } bb12: { - _61 = core::panicking::AssertKind::Eq; - _63 = std::option::Option::None; - _62 = core::panicking::assert_failed::<usize, usize>(move _61, _56, _57, move _63) -> unwind unreachable; + _63 = core::panicking::AssertKind::Eq; + _65 = std::option::Option::None; + _64 = core::panicking::assert_failed::<usize, usize>(move _63, _58, _59, move _65) -> unwind unreachable; } } fn operands::{constant#0}() -> usize { diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.rs b/tests/ui/statics/unsizing-wfcheck-issue-127299.rs index cd15be54ec7..fd07937d90f 100644 --- a/tests/ui/statics/unsizing-wfcheck-issue-127299.rs +++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.rs @@ -6,12 +6,12 @@ trait Qux { pub struct Lint { pub desc: &'static dyn Qux, - //~^ ERROR cannot be made into an object + //~^ ERROR is not dyn compatible } static FOO: &Lint = &Lint { desc: "desc" }; //~^ ERROR cannot be shared between threads safely -//~| ERROR cannot be made into an object -//~| ERROR cannot be made into an object +//~| ERROR is not dyn compatible +//~| ERROR is not dyn compatible fn main() {} diff --git a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr index 35dd570e91f..08c744979f5 100644 --- a/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr +++ b/tests/ui/statics/unsizing-wfcheck-issue-127299.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Qux` cannot be made into an object +error[E0038]: the trait `Qux` is not dyn compatible --> $DIR/unsizing-wfcheck-issue-127299.rs:8:24 | LL | pub desc: &'static dyn Qux, - | ^^^^^^^ `Qux` cannot be made into an object + | ^^^^^^^ `Qux` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 | LL | trait Qux { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar() -> i32; | ^^^ ...because associated function `bar` has no `self` parameter help: consider turning `bar` into a method by giving it a `&self` argument @@ -36,17 +37,18 @@ LL | pub struct Lint { = note: required because it appears within the type `&'static Lint` = note: shared static variables must have a type that implements `Sync` -error[E0038]: the trait `Qux` cannot be made into an object +error[E0038]: the trait `Qux` is not dyn compatible --> $DIR/unsizing-wfcheck-issue-127299.rs:12:35 | LL | static FOO: &Lint = &Lint { desc: "desc" }; - | ^^^^^^ `Qux` cannot be made into an object + | ^^^^^^ `Qux` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 | LL | trait Qux { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar() -> i32; | ^^^ ...because associated function `bar` has no `self` parameter = note: required for the cast from `&'static str` to `&'static (dyn Qux + 'static)` @@ -59,17 +61,18 @@ help: alternatively, consider constraining `bar` so it does not apply to trait o LL | fn bar() -> i32 where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Qux` cannot be made into an object +error[E0038]: the trait `Qux` is not dyn compatible --> $DIR/unsizing-wfcheck-issue-127299.rs:12:35 | LL | static FOO: &Lint = &Lint { desc: "desc" }; - | ^^^^^^ `Qux` cannot be made into an object + | ^^^^^^ `Qux` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/unsizing-wfcheck-issue-127299.rs:4:8 | LL | trait Qux { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn bar() -> i32; | ^^^ ...because associated function `bar` has no `self` parameter help: consider turning `bar` into a method by giving it a `&self` argument diff --git a/tests/ui/structs/default-field-values/empty-struct.rs b/tests/ui/structs/default-field-values/empty-struct.rs new file mode 100644 index 00000000000..c9cb861ae27 --- /dev/null +++ b/tests/ui/structs/default-field-values/empty-struct.rs @@ -0,0 +1,21 @@ +#![feature(default_field_values)] + +// If an API wants users to always use `..` even if they specify all the fields, they should use a +// sentinel field. As of now, that field can't be made private so it is only constructable with this +// syntax, but this might change in the future. + +struct A {} +struct B(); +struct C; +struct D { + x: i32, +} +struct E(i32); + +fn main() { + let _ = A { .. }; //~ ERROR has no fields + let _ = B { .. }; //~ ERROR has no fields + let _ = C { .. }; //~ ERROR has no fields + let _ = D { x: 0, .. }; + let _ = E { 0: 0, .. }; +} diff --git a/tests/ui/structs/default-field-values/empty-struct.stderr b/tests/ui/structs/default-field-values/empty-struct.stderr new file mode 100644 index 00000000000..079e83415b4 --- /dev/null +++ b/tests/ui/structs/default-field-values/empty-struct.stderr @@ -0,0 +1,26 @@ +error: `A` has no fields, `..` needs at least one default field in the struct definition + --> $DIR/empty-struct.rs:16:17 + | +LL | let _ = A { .. }; + | - ^^ + | | + | this type has no fields + +error: `B` has no fields, `..` needs at least one default field in the struct definition + --> $DIR/empty-struct.rs:17:17 + | +LL | let _ = B { .. }; + | - ^^ + | | + | this type has no fields + +error: `C` has no fields, `..` needs at least one default field in the struct definition + --> $DIR/empty-struct.rs:18:17 + | +LL | let _ = C { .. }; + | - ^^ + | | + | this type has no fields + +error: aborting due to 3 previous errors + diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr new file mode 100644 index 00000000000..63793425657 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.disabled.stderr @@ -0,0 +1,86 @@ +error[E0658]: default values on fields are experimental + --> $DIR/non-exhaustive-ctor.rs:9:22 + | +LL | pub field: () = (), + | ^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` 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]: default values on fields are experimental + --> $DIR/non-exhaustive-ctor.rs:11:25 + | +LL | pub field1: Priv = Priv, + | ^^^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` 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]: default values on fields are experimental + --> $DIR/non-exhaustive-ctor.rs:13:25 + | +LL | pub field2: Priv = Priv, + | ^^^^^^^ + | + = note: see issue #132162 <https://github.com/rust-lang/rust/issues/132162> for more information + = help: add `#![feature(default_field_values)]` 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[E0797]: base expression required after `..` + --> $DIR/non-exhaustive-ctor.rs:20:19 + | +LL | let _ = S { .. }; // ok + | ^ + | +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | +help: add a base expression here + | +LL | let _ = S { ../* expr */ }; // ok + | ++++++++++ + +error[E0797]: base expression required after `..` + --> $DIR/non-exhaustive-ctor.rs:22:30 + | +LL | let _ = S { field: (), .. }; // ok + | ^ + | +help: add `#![feature(default_field_values)]` to the crate attributes to enable default values on `struct` fields + | +LL + #![feature(default_field_values)] + | +help: add a base expression here + | +LL | let _ = S { field: (), ../* expr */ }; // ok + | ++++++++++ + +error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:24:13 + | +LL | let _ = S { }; + | ^ missing `field`, `field1` and `field2` + | +help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..` + | +LL | let _ = S { .. }; + | ~~~~~~ + +error[E0063]: missing fields `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:26:13 + | +LL | let _ = S { field: () }; + | ^ missing `field1` and `field2` + | +help: all remaining fields have default values, if you added `#![feature(default_field_values)]` to your crate you could use those values with `..` + | +LL | let _ = S { field: (), .. }; + | ++++ + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0063, E0658, E0797. +For more information about an error, try `rustc --explain E0063`. diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed new file mode 100644 index 00000000000..7a371f993e8 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.fixed @@ -0,0 +1,28 @@ +//@ revisions: enabled disabled +//@[enabled] run-rustfix +#![allow(private_interfaces, dead_code)] +#![cfg_attr(enabled, feature(default_field_values))] +use m::S; + +mod m { + pub struct S { + pub field: () = (), + //[disabled]~^ ERROR default values on fields are experimental + pub field1: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + pub field2: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + } + struct Priv; +} + +fn main() { + let _ = S { .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { field: (), .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { .. }; + //~^ ERROR missing fields `field`, `field1` and `field2` + let _ = S { field: (), .. }; + //~^ ERROR missing fields `field1` and `field2` +} diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr new file mode 100644 index 00000000000..6d035ebdc47 --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.enabled.stderr @@ -0,0 +1,25 @@ +error[E0063]: missing fields `field`, `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:24:13 + | +LL | let _ = S { }; + | ^ missing `field`, `field1` and `field2` + | +help: all remaining fields have default values, you can use those values with `..` + | +LL | let _ = S { .. }; + | ~~~~~~ + +error[E0063]: missing fields `field1` and `field2` in initializer of `S` + --> $DIR/non-exhaustive-ctor.rs:26:13 + | +LL | let _ = S { field: () }; + | ^ missing `field1` and `field2` + | +help: all remaining fields have default values, you can use those values with `..` + | +LL | let _ = S { field: (), .. }; + | ++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0063`. diff --git a/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs b/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs new file mode 100644 index 00000000000..b60b219f8bc --- /dev/null +++ b/tests/ui/structs/default-field-values/non-exhaustive-ctor.rs @@ -0,0 +1,28 @@ +//@ revisions: enabled disabled +//@[enabled] run-rustfix +#![allow(private_interfaces, dead_code)] +#![cfg_attr(enabled, feature(default_field_values))] +use m::S; + +mod m { + pub struct S { + pub field: () = (), + //[disabled]~^ ERROR default values on fields are experimental + pub field1: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + pub field2: Priv = Priv, + //[disabled]~^ ERROR default values on fields are experimental + } + struct Priv; +} + +fn main() { + let _ = S { .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { field: (), .. }; // ok + //[disabled]~^ ERROR base expression required after `..` + let _ = S { }; + //~^ ERROR missing fields `field`, `field1` and `field2` + let _ = S { field: () }; + //~^ ERROR missing fields `field1` and `field2` +} diff --git a/tests/ui/structs/default-field-values/visibility.rs b/tests/ui/structs/default-field-values/visibility.rs new file mode 100644 index 00000000000..ff1245551b0 --- /dev/null +++ b/tests/ui/structs/default-field-values/visibility.rs @@ -0,0 +1,42 @@ +#![feature(default_field_values)] +pub mod foo { + #[derive(Default)] + pub struct Alpha { + beta: u8 = 42, + gamma: bool = true, + } +} + +mod bar { + use crate::foo::Alpha; + fn baz() { + let _x = Alpha { .. }; + //~^ ERROR fields `beta` and `gamma` of struct `Alpha` are private + let _x = Alpha { + beta: 0, //~ ERROR fields `beta` and `gamma` of struct `Alpha` are private + gamma: false, + }; + let _x = Alpha { + beta: 0, //~ ERROR fields `beta` and `gamma` of struct `Alpha` are private + .. + }; + let _x = Alpha { beta: 0, .. }; + //~^ ERROR fields `beta` and `gamma` of struct `Alpha` are private + let _x = Alpha { beta: 0, ..Default::default() }; + //~^ ERROR fields `beta` and `gamma` of struct `Alpha` are private + } +} + +pub mod baz { + pub struct S { + x: i32 = 1, + } +} +fn main() { + let _a = baz::S { + .. //~ ERROR field `x` of struct `S` is private + }; + let _b = baz::S { + x: 0, //~ ERROR field `x` of struct `S` is private + }; +} diff --git a/tests/ui/structs/default-field-values/visibility.stderr b/tests/ui/structs/default-field-values/visibility.stderr new file mode 100644 index 00000000000..38b96033252 --- /dev/null +++ b/tests/ui/structs/default-field-values/visibility.stderr @@ -0,0 +1,61 @@ +error[E0451]: field `x` of struct `S` is private + --> $DIR/visibility.rs:37:9 + | +LL | let _a = baz::S { + | ------ in this type +LL | .. + | ^^ field `x` is private + +error[E0451]: field `x` of struct `S` is private + --> $DIR/visibility.rs:40:9 + | +LL | let _b = baz::S { + | ------ in this type +LL | x: 0, + | ^ private field + +error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private + --> $DIR/visibility.rs:13:26 + | +LL | let _x = Alpha { .. }; + | ^^ fields `beta` and `gamma` are private + +error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private + --> $DIR/visibility.rs:16:13 + | +LL | let _x = Alpha { + | ----- in this type +LL | beta: 0, + | ^^^^ private field +LL | gamma: false, + | ^^^^^ private field + +error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private + --> $DIR/visibility.rs:20:13 + | +LL | let _x = Alpha { + | ----- in this type +LL | beta: 0, + | ^^^^^^^ private field +LL | .. + | ^^ field `gamma` is private + +error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private + --> $DIR/visibility.rs:23:26 + | +LL | let _x = Alpha { beta: 0, .. }; + | ^^^^^^^ ^^ field `gamma` is private + | | + | private field + +error[E0451]: fields `beta` and `gamma` of struct `Alpha` are private + --> $DIR/visibility.rs:25:26 + | +LL | let _x = Alpha { beta: 0, ..Default::default() }; + | ^^^^^^^ ^^^^^^^^^^^^^^^^^^ field `gamma` is private + | | + | private field + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0451`. diff --git a/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs index 4b3d5faba46..66b435247d4 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-references-self.rs @@ -6,10 +6,10 @@ trait Trait { //~| ERROR the size for values of type `Self` cannot be known } -fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` cannot be made into an object +fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` is not dyn compatible trait Other: Sized {} -fn foo(x: &dyn Other) {} //~ ERROR the trait `Other` cannot be made into an object +fn foo(x: &dyn Other) {} //~ ERROR the trait `Other` is not dyn compatible fn main() {} diff --git a/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr index 242c44abd9d..cb0e7fce910 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-references-self.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/dyn-incompatible-trait-references-self.rs:9:12 | LL | fn bar(x: &dyn Trait) {} - | ^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-references-self.rs:2:22 | LL | trait Trait { - | ----- this trait cannot be made into an object... + | ----- this trait is not dyn compatible... LL | fn baz(&self, _: Self) {} | ^^^^ ...because method `baz` references the `Self` type in this parameter LL | @@ -17,19 +18,20 @@ LL | fn bat(&self) -> Self {} = help: consider moving `baz` to another trait = help: consider moving `bat` to another trait -error[E0038]: the trait `Other` cannot be made into an object +error[E0038]: the trait `Other` is not dyn compatible --> $DIR/dyn-incompatible-trait-references-self.rs:13:12 | LL | fn foo(x: &dyn Other) {} - | ^^^^^^^^^ `Other` cannot be made into an object + | ^^^^^^^^^ `Other` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-references-self.rs:11:14 | LL | trait Other: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... error[E0277]: the size for values of type `Self` cannot be known at compilation time --> $DIR/dyn-incompatible-trait-references-self.rs:2:22 diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs index 4ab10f40eb6..747926c400a 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.rs @@ -3,12 +3,12 @@ trait A: Sized { fn f(a: dyn A) -> dyn A; //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `A` cannot be made into an object + //~| ERROR the trait `A` is not dyn compatible } trait B { fn f(a: dyn B) -> dyn B; //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `B` cannot be made into an object + //~| ERROR the trait `B` is not dyn compatible } trait C { fn f(&self, a: dyn C) -> dyn C; diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr index 5e0d1a14452..2efcad1e7bd 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self-2021.stderr @@ -11,19 +11,20 @@ help: you might have meant to use `Self` to refer to the implementing type LL | fn f(a: Self) -> Self; | ~~~~ ~~~~ -error[E0038]: the trait `A` cannot be made into an object +error[E0038]: the trait `A` is not dyn compatible --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:4:13 | LL | fn f(a: dyn A) -> dyn A; - | ^^^^^ `A` cannot be made into an object + | ^^^^^ `A` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:3:10 | LL | trait A: Sized { | - ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... error: associated item referring to unboxed trait object for its own trait --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13 @@ -38,17 +39,18 @@ help: you might have meant to use `Self` to refer to the implementing type LL | fn f(a: Self) -> Self; | ~~~~ ~~~~ -error[E0038]: the trait `B` cannot be made into an object +error[E0038]: the trait `B` is not dyn compatible --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:13 | LL | fn f(a: dyn B) -> dyn B; - | ^^^^^ `B` cannot be made into an object + | ^^^^^ `B` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-should-use-self-2021.rs:9:8 | LL | trait B { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | fn f(a: dyn B) -> dyn B; | ^ ...because associated function `f` has no `self` parameter help: consider turning `f` into a method by giving it a `&self` argument diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs index 75f99075eb1..2893bbc8b71 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.rs @@ -2,12 +2,12 @@ trait A: Sized { fn f(a: A) -> A; //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `A` cannot be made into an object + //~| ERROR the trait `A` is not dyn compatible } trait B { fn f(a: B) -> B; //~^ ERROR associated item referring to unboxed trait object for its own trait - //~| ERROR the trait `B` cannot be made into an object + //~| ERROR the trait `B` is not dyn compatible } trait C { fn f(&self, a: C) -> C; diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr index 93f6ea2b12e..ecb3ee9185f 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-self.stderr @@ -11,19 +11,20 @@ help: you might have meant to use `Self` to refer to the implementing type LL | fn f(a: Self) -> Self; | ~~~~ ~~~~ -error[E0038]: the trait `A` cannot be made into an object +error[E0038]: the trait `A` is not dyn compatible --> $DIR/dyn-incompatible-trait-should-use-self.rs:3:13 | LL | fn f(a: A) -> A; - | ^ `A` cannot be made into an object + | ^ `A` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-should-use-self.rs:2:10 | LL | trait A: Sized { | - ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... error: associated item referring to unboxed trait object for its own trait --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13 @@ -38,17 +39,18 @@ help: you might have meant to use `Self` to refer to the implementing type LL | fn f(a: Self) -> Self; | ~~~~ ~~~~ -error[E0038]: the trait `B` cannot be made into an object +error[E0038]: the trait `B` is not dyn compatible --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:13 | LL | fn f(a: B) -> B; - | ^ `B` cannot be made into an object + | ^ `B` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-should-use-self.rs:8:8 | LL | trait B { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | fn f(a: B) -> B; | ^ ...because associated function `f` has no `self` parameter help: consider turning `f` into a method by giving it a `&self` argument diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed index fd9b78934c7..2b26d8cc82e 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.fixed @@ -6,7 +6,7 @@ trait Trait { fn bar(self: &Self) {} //~ ERROR invalid `self` parameter type } -fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` cannot be made into an object +fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` is not dyn compatible trait Other {} diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs index e4aa0d89239..b0b02dedb2b 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.rs @@ -6,7 +6,7 @@ trait Trait { fn bar(self: ()) {} //~ ERROR invalid `self` parameter type } -fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` cannot be made into an object +fn bar(x: &dyn Trait) {} //~ ERROR the trait `Trait` is not dyn compatible trait Other {} diff --git a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr index beafd7c2ab0..696840d3ba4 100644 --- a/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr +++ b/tests/ui/suggestions/dyn-incompatible-trait-should-use-where-sized.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/dyn-incompatible-trait-should-use-where-sized.rs:9:12 | LL | fn bar(x: &dyn Trait) {} - | ^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/dyn-incompatible-trait-should-use-where-sized.rs:5:8 | LL | trait Trait { - | ----- this trait cannot be made into an object... + | ----- this trait is not dyn compatible... LL | fn foo() where Self: Other, { } | ^^^ ...because associated function `foo` has no `self` parameter LL | fn bar(self: ()) {} diff --git a/tests/ui/suggestions/issue-116434-2015.rs b/tests/ui/suggestions/issue-116434-2015.rs index 2e94473eb1a..1518765152f 100644 --- a/tests/ui/suggestions/issue-116434-2015.rs +++ b/tests/ui/suggestions/issue-116434-2015.rs @@ -7,7 +7,7 @@ trait Foo { //~| WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects] //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| HELP if this is a dyn-compatible trait, use `dyn` - //~| ERROR the trait `Clone` cannot be made into an object [E0038] + //~| ERROR the trait `Clone` is not dyn compatible [E0038] //~| HELP there is an associated type with the same name } @@ -22,7 +22,7 @@ trait DbInterface { //~| WARNING trait objects without an explicit `dyn` are deprecated [bare_trait_objects] //~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //~| HELP if this is a dyn-compatible trait, use `dyn` - //~| ERROR the trait `DbHandle` cannot be made into an object [E0038] + //~| ERROR the trait `DbHandle` is not dyn compatible [E0038] //~| HELP there is an associated type with the same name } diff --git a/tests/ui/suggestions/issue-116434-2015.stderr b/tests/ui/suggestions/issue-116434-2015.stderr index 24fc87f765f..508c3ec5e4f 100644 --- a/tests/ui/suggestions/issue-116434-2015.stderr +++ b/tests/ui/suggestions/issue-116434-2015.stderr @@ -39,14 +39,15 @@ help: if this is a dyn-compatible trait, use `dyn` LL | fn foo() -> dyn Clone; | +++ -error[E0038]: the trait `Clone` cannot be made into an object +error[E0038]: the trait `Clone` is not dyn compatible --> $DIR/issue-116434-2015.rs:3:17 | LL | fn foo() -> Clone; - | ^^^^^ `Clone` cannot be made into an object + | ^^^^^ `Clone` is not dyn compatible | - = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "dyn-compatible" 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> + = note: the trait is not dyn compatible because it requires `Self: Sized` + = note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> help: there is an associated type with the same name | LL | fn foo() -> Self::Clone; @@ -66,19 +67,20 @@ help: if this is a dyn-compatible trait, use `dyn` LL | fn handle() -> dyn DbHandle; | +++ -error[E0038]: the trait `DbHandle` cannot be made into an object +error[E0038]: the trait `DbHandle` is not dyn compatible --> $DIR/issue-116434-2015.rs:18:20 | LL | fn handle() -> DbHandle; - | ^^^^^^^^ `DbHandle` cannot be made into an object + | ^^^^^^^^ `DbHandle` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-116434-2015.rs:14:17 | LL | trait DbHandle: Sized {} | -------- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... + | this trait is not dyn compatible... help: there is an associated type with the same name | LL | fn handle() -> Self::DbHandle; diff --git a/tests/ui/suggestions/issue-98500.rs b/tests/ui/suggestions/issue-98500.rs index 289b16abf4b..869b665c8cb 100644 --- a/tests/ui/suggestions/issue-98500.rs +++ b/tests/ui/suggestions/issue-98500.rs @@ -9,6 +9,6 @@ pub trait B where } struct S(Box<dyn B>); -//~^ ERROR the trait `B` cannot be made into an object +//~^ ERROR the trait `B` is not dyn compatible fn main() {} diff --git a/tests/ui/suggestions/issue-98500.stderr b/tests/ui/suggestions/issue-98500.stderr index d7136ec1a64..97b712acfcb 100644 --- a/tests/ui/suggestions/issue-98500.stderr +++ b/tests/ui/suggestions/issue-98500.stderr @@ -1,10 +1,11 @@ -error[E0038]: the trait `B` cannot be made into an object +error[E0038]: the trait `B` is not dyn compatible --> $DIR/issue-98500.rs:11:14 | LL | struct S(Box<dyn B>); - | ^^^^^ `B` cannot be made into an object + | ^^^^^ `B` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/auxiliary/dyn-incompatible.rs:4:8 | LL | fn f(); @@ -15,7 +16,7 @@ LL | fn f2(self: &Arc<Self>); ::: $DIR/issue-98500.rs:5:11 | LL | pub trait B where - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... = help: consider moving `f` to another trait = help: consider moving `f2` to another trait diff --git a/tests/ui/test-attrs/test-runner-hides-start.rs b/tests/ui/test-attrs/test-runner-hides-start.rs deleted file mode 100644 index 444ac237cfa..00000000000 --- a/tests/ui/test-attrs/test-runner-hides-start.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass -//@ compile-flags: --test - -#![feature(start)] - -#[start] -fn start(_: isize, _: *const *const u8) -> isize { panic!(); } diff --git a/tests/ui/traits/alias/generic-default-in-dyn.rs b/tests/ui/traits/alias/generic-default-in-dyn.rs index d44e1c2a975..b263e578c31 100644 --- a/tests/ui/traits/alias/generic-default-in-dyn.rs +++ b/tests/ui/traits/alias/generic-default-in-dyn.rs @@ -2,9 +2,9 @@ trait SendEqAlias<T> = PartialEq; //~^ ERROR trait aliases are experimental struct Foo<T>(dyn SendEqAlias<T>); -//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393] +//~^ ERROR the trait alias `SendEqAlias` is not dyn compatible struct Bar<T>(dyn SendEqAlias<T>, T); -//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393] +//~^ ERROR the trait alias `SendEqAlias` is not dyn compatible fn main() {} diff --git a/tests/ui/traits/alias/generic-default-in-dyn.stderr b/tests/ui/traits/alias/generic-default-in-dyn.stderr index 50031e184c1..1ab9e6d5c5c 100644 --- a/tests/ui/traits/alias/generic-default-in-dyn.stderr +++ b/tests/ui/traits/alias/generic-default-in-dyn.stderr @@ -8,29 +8,37 @@ LL | trait SendEqAlias<T> = PartialEq; = help: add `#![feature(trait_alias)]` 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[E0393]: the type parameter `Rhs` must be explicitly specified +error[E0038]: the trait alias `SendEqAlias` is not dyn compatible --> $DIR/generic-default-in-dyn.rs:4:19 | LL | struct Foo<T>(dyn SendEqAlias<T>); - | ^^^^^^^^^^^^^^ missing reference to `Rhs` - --> $SRC_DIR/core/src/cmp.rs:LL:COL + | ^^^^^^^^^^^^^^ `SendEqAlias` is not dyn compatible | - = note: type parameter `Rhs` must be specified for this +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/generic-default-in-dyn.rs:1:24 | - = note: because of the default `Self` reference, type parameters must be specified on object types +LL | trait SendEqAlias<T> = PartialEq; + | ----------- ^^^^^^^^^ ...because it uses `Self` as a type parameter + | | + | this trait is not dyn compatible... -error[E0393]: the type parameter `Rhs` must be explicitly specified +error[E0038]: the trait alias `SendEqAlias` is not dyn compatible --> $DIR/generic-default-in-dyn.rs:7:19 | LL | struct Bar<T>(dyn SendEqAlias<T>, T); - | ^^^^^^^^^^^^^^ missing reference to `Rhs` - --> $SRC_DIR/core/src/cmp.rs:LL:COL + | ^^^^^^^^^^^^^^ `SendEqAlias` is not dyn compatible | - = note: type parameter `Rhs` must be specified for this +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/generic-default-in-dyn.rs:1:24 | - = note: because of the default `Self` reference, type parameters must be specified on object types +LL | trait SendEqAlias<T> = PartialEq; + | ----------- ^^^^^^^^^ ...because it uses `Self` as a type parameter + | | + | this trait is not dyn compatible... error: aborting due to 3 previous errors -Some errors have detailed explanations: E0393, E0658. -For more information about an error, try `rustc --explain E0393`. +Some errors have detailed explanations: E0038, E0658. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/alias/no-duplicates.stderr b/tests/ui/traits/alias/no-duplicates.stderr index bf244b97e9b..6a901a80554 100644 --- a/tests/ui/traits/alias/no-duplicates.stderr +++ b/tests/ui/traits/alias/no-duplicates.stderr @@ -4,32 +4,32 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _0 = Obj; | --- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait ... LL | type _T00 = dyn _0 + _0; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-duplicates.rs:19:22 + --> $DIR/no-duplicates.rs:19:17 | LL | trait _0 = Obj; | --- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T01 = dyn _1 + _0; - | -- ^^ trait alias used in trait object type (additional use) + | ^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -40,18 +40,18 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _0 = Obj; | --- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait LL | trait _1 = _0; | -- | | - | referenced here (additional use) - | referenced here (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias ... LL | type _T02 = dyn _1 + _1; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -62,10 +62,10 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _0 = Obj; | --- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T03 = dyn Obj + _1; - | --- ^^ trait alias used in trait object type (additional use) + | --- ^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -73,17 +73,17 @@ LL | type _T03 = dyn Obj + _1; = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-duplicates.rs:28:22 + --> $DIR/no-duplicates.rs:28:17 | LL | trait _0 = Obj; - | --- first non-auto trait + | --- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T04 = dyn _1 + Obj; - | -- ^^^ additional non-auto trait + | ^^ --- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -92,23 +92,17 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec --> $DIR/no-duplicates.rs:37:17 | LL | trait _0 = Obj; - | --- - | | - | additional non-auto trait - | first non-auto trait -LL | trait _1 = _0; - | -- referenced here (additional use) + | --- additional non-auto trait ... LL | trait _2 = _0 + _1; - | -- -- referenced here (additional use) - | | - | referenced here (first use) + | -- second non-auto trait comes from this alias +LL | trait _3 = Obj; + | --- first non-auto trait ... LL | type _T10 = dyn _2 + _3; - | ^^ + | ^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -120,14 +114,14 @@ LL | trait _0 = Obj; | --- additional non-auto trait ... LL | trait _2 = _0 + _1; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias LL | trait _3 = Obj; | --- first non-auto trait ... LL | type _T11 = dyn _3 + _2; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -139,10 +133,10 @@ LL | trait _0 = Obj; | --- additional non-auto trait ... LL | trait _2 = _0 + _1; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T12 = dyn Obj + _2; - | --- ^^ trait alias used in trait object type (additional use) + | --- ^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -153,42 +147,34 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec --> $DIR/no-duplicates.rs:46:17 | LL | trait _0 = Obj; - | --- - | | - | additional non-auto trait - | first non-auto trait -LL | trait _1 = _0; - | -- referenced here (additional use) + | --- additional non-auto trait ... LL | trait _2 = _0 + _1; - | -- -- referenced here (additional use) - | | - | referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T13 = dyn _2 + Obj; - | ^^ + | ^^ --- first non-auto trait | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-duplicates.rs:49:22 + --> $DIR/no-duplicates.rs:49:17 | LL | trait _0 = Obj; - | --- first non-auto trait + | --- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | trait _3 = Obj; - | --- additional non-auto trait + | --- first non-auto trait ... LL | type _T14 = dyn _1 + _3; - | -- ^^ trait alias used in trait object type (additional use) + | ^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -199,15 +185,15 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _0 = Obj; | --- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | trait _3 = Obj; | --- first non-auto trait ... LL | type _T15 = dyn _3 + _1; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -218,17 +204,17 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _0 = Obj; | --- first non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- first non-auto trait comes from this alias ... LL | trait _3 = Obj; | --- additional non-auto trait LL | trait _4 = _3; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T16 = dyn _1 + _4; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -239,17 +225,17 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _0 = Obj; | --- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | trait _3 = Obj; | --- first non-auto trait LL | trait _4 = _3; - | -- referenced here (first use) + | -- first non-auto trait comes from this alias ... LL | type _T17 = dyn _4 + _1; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -260,13 +246,13 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _5 = Obj + Send; | --- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait LL | LL | type _T20 = dyn _5 + _5; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -278,7 +264,7 @@ LL | trait _5 = Obj + Send; | --- additional non-auto trait ... LL | type _T21 = dyn Obj + _5; - | --- ^^ trait alias used in trait object type (additional use) + | --- ^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -286,29 +272,29 @@ LL | type _T21 = dyn Obj + _5; = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-duplicates.rs:71:22 + --> $DIR/no-duplicates.rs:71:17 | LL | trait _5 = Obj + Send; - | --- first non-auto trait + | --- additional non-auto trait ... LL | type _T22 = dyn _5 + Obj; - | -- ^^^ additional non-auto trait + | ^^ --- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-duplicates.rs:74:36 + --> $DIR/no-duplicates.rs:74:17 | LL | trait _5 = Obj + Send; - | --- first non-auto trait + | --- additional non-auto trait ... LL | type _T23 = dyn _5 + Send + Sync + Obj; - | -- ^^^ additional non-auto trait + | ^^ --- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -319,19 +305,19 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _5 = Obj + Send; | --- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait ... LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send - | -- -- referenced here (additional use) + | -- -- second non-auto trait comes from this alias | | - | referenced here (first use) + | first non-auto trait comes from this alias LL | LL | type _T30 = dyn _6; | ^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -342,19 +328,19 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _5 = Obj + Send; | --- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait ... LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send - | -- -- referenced here (additional use) + | -- -- second non-auto trait comes from this alias | | - | referenced here (first use) + | first non-auto trait comes from this alias ... LL | type _T31 = dyn _6 + Send; | ^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -365,38 +351,38 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _5 = Obj + Send; | --- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait ... LL | trait _6 = _5 + _5; // ==> Obj + Send + Obj + Send - | -- -- referenced here (additional use) + | -- -- second non-auto trait comes from this alias | | - | referenced here (first use) + | first non-auto trait comes from this alias ... LL | type _T32 = dyn Send + _6; | ^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-duplicates.rs:95:22 + --> $DIR/no-duplicates.rs:95:17 | LL | trait _5 = Obj + Send; - | --- first non-auto trait + | --- additional non-auto trait ... LL | trait _7 = _5 + Sync; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias LL | trait _8 = Unpin + _7; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias LL | LL | type _T40 = dyn _8 + Obj; - | -- ^^^ additional non-auto trait + | ^^ --- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -408,12 +394,12 @@ LL | trait _5 = Obj + Send; | --- additional non-auto trait ... LL | trait _7 = _5 + Sync; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias LL | trait _8 = Unpin + _7; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T41 = dyn Obj + _8; - | --- ^^ trait alias used in trait object type (additional use) + | --- ^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -421,25 +407,25 @@ LL | type _T41 = dyn Obj + _8; = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-duplicates.rs:101:22 + --> $DIR/no-duplicates.rs:101:17 | LL | trait _3 = Obj; - | --- additional non-auto trait + | --- first non-auto trait LL | trait _4 = _3; - | -- referenced here (additional use) + | -- first non-auto trait comes from this alias ... LL | trait _5 = Obj + Send; - | --- first non-auto trait + | --- additional non-auto trait ... LL | trait _7 = _5 + Sync; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias LL | trait _8 = Unpin + _7; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T42 = dyn _8 + _4; - | -- ^^ trait alias used in trait object type (additional use) + | ^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -450,20 +436,20 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _3 = Obj; | --- first non-auto trait LL | trait _4 = _3; - | -- referenced here (first use) + | -- first non-auto trait comes from this alias ... LL | trait _5 = Obj + Send; | --- additional non-auto trait ... LL | trait _7 = _5 + Sync; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias LL | trait _8 = Unpin + _7; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T43 = dyn _4 + _8; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -474,20 +460,20 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _3 = Obj; | --- first non-auto trait LL | trait _4 = _3; - | -- referenced here (first use) + | -- first non-auto trait comes from this alias ... LL | trait _5 = Obj + Send; | --- additional non-auto trait ... LL | trait _7 = _5 + Sync; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias LL | trait _8 = Unpin + _7; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T44 = dyn _4 + Send + Sync + _8; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Obj + Obj {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -500,9 +486,9 @@ LL | trait _9 = for<'a> ObjL<'a>; LL | trait _10 = for<'b> ObjL<'b>; | ---------------- additional non-auto trait LL | type _T50 = dyn _9 + _10; - | -- ^^^ trait alias used in trait object type (additional use) + | -- ^^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: for<'a> ObjL<'a> + for<'b> ObjL<'b> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -515,9 +501,9 @@ LL | trait _11 = ObjT<for<'a> fn(&'a u8)>; LL | trait _12 = ObjT<for<'b> fn(&'b u8)>; | ------------------------ additional non-auto trait LL | type _T60 = dyn _11 + _12; - | --- ^^^ trait alias used in trait object type (additional use) + | --- ^^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjT<for<'a> fn(&'a u8)> + ObjT<for<'b> fn(&'b u8)> {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> diff --git a/tests/ui/traits/alias/no-extra-traits.stderr b/tests/ui/traits/alias/no-extra-traits.stderr index 4b1ddf6843c..fcdb4937ff5 100644 --- a/tests/ui/traits/alias/no-extra-traits.stderr +++ b/tests/ui/traits/alias/no-extra-traits.stderr @@ -1,15 +1,15 @@ error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:16:22 + --> $DIR/no-extra-traits.rs:16:17 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait ... LL | type _T00 = dyn _0 + ObjB; - | -- ^^^^ additional non-auto trait + | ^^ ---- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object @@ -19,7 +19,7 @@ LL | trait _0 = ObjA; | ---- additional non-auto trait ... LL | type _T01 = dyn ObjB + _0; - | ---- ^^ trait alias used in trait object type (additional use) + | ---- ^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -32,10 +32,10 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _0 = ObjA; | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T02 = dyn ObjB + _1; - | ---- ^^ trait alias used in trait object type (additional use) + | ---- ^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -43,19 +43,19 @@ LL | type _T02 = dyn ObjB + _1; = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:25:22 + --> $DIR/no-extra-traits.rs:25:17 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T03 = dyn _1 + ObjB; - | -- ^^^^ additional non-auto trait + | ^^ ---- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object @@ -64,34 +64,34 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _2 = ObjB; | ---- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait LL | trait _3 = _2; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T10 = dyn _2 + _3; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:37:22 + --> $DIR/no-extra-traits.rs:37:17 | LL | trait _2 = ObjB; | ---- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait LL | trait _3 = _2; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T11 = dyn _3 + _2; - | -- ^^ trait alias used in trait object type (additional use) + | ^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -102,38 +102,38 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _2 = ObjB; | ---- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait LL | trait _3 = _2; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias LL | trait _4 = _3; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T12 = dyn _2 + _4; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:43:22 + --> $DIR/no-extra-traits.rs:43:17 | LL | trait _2 = ObjB; | ---- | | - | additional non-auto trait | first non-auto trait + | additional non-auto trait LL | trait _3 = _2; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias LL | trait _4 = _3; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T13 = dyn _4 + _2; - | -- ^^ trait alias used in trait object type (additional use) + | ^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> @@ -144,50 +144,50 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _0 = ObjA; | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; | ---- first non-auto trait LL | LL | type _T20 = dyn _5 + _1; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:53:22 + --> $DIR/no-extra-traits.rs:53:17 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- additional non-auto trait + | ---- first non-auto trait ... LL | type _T21 = dyn _1 + _5; - | -- ^^ trait alias used in trait object type (additional use) + | ^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:56:22 + --> $DIR/no-extra-traits.rs:56:17 | LL | trait _5 = Sync + ObjB + Send; - | ---- first non-auto trait + | ---- additional non-auto trait ... LL | type _T22 = dyn _5 + ObjA; - | -- ^^^^ additional non-auto trait + | ^^ ---- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object @@ -197,7 +197,7 @@ LL | trait _5 = Sync + ObjB + Send; | ---- additional non-auto trait ... LL | type _T23 = dyn ObjA + _5; - | ---- ^^ trait alias used in trait object type (additional use) + | ---- ^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -210,50 +210,50 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec LL | trait _0 = ObjA; | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; | ---- first non-auto trait ... LL | type _T24 = dyn Send + _5 + _1 + Sync; - | -- ^^ trait alias used in trait object type (additional use) + | -- ^^ second non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias | = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:65:29 + --> $DIR/no-extra-traits.rs:65:17 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- additional non-auto trait + | ---- first non-auto trait ... LL | type _T25 = dyn _1 + Sync + _5 + Send; - | -- ^^ trait alias used in trait object type (additional use) + | ^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:68:36 + --> $DIR/no-extra-traits.rs:68:31 | LL | trait _5 = Sync + ObjB + Send; - | ---- first non-auto trait + | ---- additional non-auto trait ... LL | type _T26 = dyn Sync + Send + _5 + ObjA; - | -- ^^^^ additional non-auto trait + | ^^ ---- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object @@ -263,7 +263,7 @@ LL | trait _5 = Sync + ObjB + Send; | ---- additional non-auto trait ... LL | type _T27 = dyn Send + Sync + ObjA + _5; - | ---- ^^ trait alias used in trait object type (additional use) + | ---- ^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -274,199 +274,199 @@ error[E0225]: only auto traits can be used as additional traits in a trait objec --> $DIR/no-extra-traits.rs:80:17 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- additional non-auto trait + | ---- first non-auto trait ... LL | trait _6 = _1 + _5; - | -- -- referenced here (additional use) + | -- -- first non-auto trait comes from this alias | | - | referenced here (first use) + | second non-auto trait comes from this alias ... LL | type _T30 = dyn _6; | ^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/no-extra-traits.rs:83:17 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- additional non-auto trait + | ---- first non-auto trait ... LL | trait _6 = _1 + _5; - | -- -- referenced here (additional use) + | -- -- first non-auto trait comes from this alias | | - | referenced here (first use) + | second non-auto trait comes from this alias ... LL | type _T31 = dyn _6 + Send; | ^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/no-extra-traits.rs:86:24 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- additional non-auto trait + | ---- first non-auto trait ... LL | trait _6 = _1 + _5; - | -- -- referenced here (additional use) + | -- -- first non-auto trait comes from this alias | | - | referenced here (first use) + | second non-auto trait comes from this alias ... LL | type _T32 = dyn Send + _6; | ^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/no-extra-traits.rs:89:17 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- additional non-auto trait + | ---- first non-auto trait ... LL | trait _6 = _1 + _5; - | -- -- referenced here (additional use) + | -- -- first non-auto trait comes from this alias | | - | referenced here (first use) + | second non-auto trait comes from this alias LL | trait _7 = _6; | -- | | - | referenced here (additional use) - | referenced here (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias LL | trait _8 = _7; | -- | | - | referenced here (additional use) - | referenced here (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias ... LL | type _T33 = dyn _8; | ^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/no-extra-traits.rs:92:17 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- additional non-auto trait + | ---- first non-auto trait ... LL | trait _6 = _1 + _5; - | -- -- referenced here (additional use) + | -- -- first non-auto trait comes from this alias | | - | referenced here (first use) + | second non-auto trait comes from this alias LL | trait _7 = _6; | -- | | - | referenced here (additional use) - | referenced here (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias LL | trait _8 = _7; | -- | | - | referenced here (additional use) - | referenced here (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias ... LL | type _T34 = dyn _8 + Send; | ^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/no-extra-traits.rs:95:24 | LL | trait _0 = ObjA; - | ---- first non-auto trait + | ---- additional non-auto trait LL | trait _1 = _0; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- additional non-auto trait + | ---- first non-auto trait ... LL | trait _6 = _1 + _5; - | -- -- referenced here (additional use) + | -- -- first non-auto trait comes from this alias | | - | referenced here (first use) + | second non-auto trait comes from this alias LL | trait _7 = _6; | -- | | - | referenced here (additional use) - | referenced here (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias LL | trait _8 = _7; | -- | | - | referenced here (additional use) - | referenced here (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias ... LL | type _T35 = dyn Send + _8; | ^^ | | - | trait alias used in trait object type (additional use) - | trait alias used in trait object type (first use) + | first non-auto trait comes from this alias + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:103:23 + --> $DIR/no-extra-traits.rs:103:17 | LL | trait _5 = Sync + ObjB + Send; - | ---- first non-auto trait + | ---- additional non-auto trait ... LL | trait _9 = _5 + Sync; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias LL | trait _10 = Unpin + _9; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias LL | LL | type _T40 = dyn _10 + ObjA; - | --- ^^^^ additional non-auto trait + | ^^^ ---- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object @@ -476,12 +476,12 @@ LL | trait _5 = Sync + ObjB + Send; | ---- additional non-auto trait ... LL | trait _9 = _5 + Sync; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias LL | trait _10 = Unpin + _9; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T41 = dyn ObjA + _10; - | ---- ^^^ trait alias used in trait object type (additional use) + | ---- ^^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -489,46 +489,46 @@ LL | type _T41 = dyn ObjA + _10; = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:109:23 + --> $DIR/no-extra-traits.rs:109:17 | LL | trait _0 = ObjA; - | ---- additional non-auto trait + | ---- first non-auto trait LL | trait _1 = _0; - | -- referenced here (additional use) + | -- first non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- first non-auto trait + | ---- additional non-auto trait ... LL | trait _9 = _5 + Sync; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias LL | trait _10 = Unpin + _9; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T42 = dyn _10 + _1; - | --- ^^ trait alias used in trait object type (additional use) + | ^^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:112:37 + --> $DIR/no-extra-traits.rs:112:24 | LL | trait _5 = Sync + ObjB + Send; - | ---- first non-auto trait + | ---- additional non-auto trait ... LL | trait _9 = _5 + Sync; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias LL | trait _10 = Unpin + _9; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T43 = dyn Send + _10 + Sync + ObjA; - | --- ^^^^ additional non-auto trait + | ^^^ ---- first non-auto trait | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object @@ -538,12 +538,12 @@ LL | trait _5 = Sync + ObjB + Send; | ---- additional non-auto trait ... LL | trait _9 = _5 + Sync; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias LL | trait _10 = Unpin + _9; - | -- referenced here (additional use) + | -- second non-auto trait comes from this alias ... LL | type _T44 = dyn ObjA + _10 + Send + Sync; - | ---- ^^^ trait alias used in trait object type (additional use) + | ---- ^^^ second non-auto trait comes from this alias | | | first non-auto trait | @@ -551,27 +551,27 @@ LL | type _T44 = dyn ObjA + _10 + Send + Sync; = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/no-extra-traits.rs:118:37 + --> $DIR/no-extra-traits.rs:118:31 | LL | trait _0 = ObjA; - | ---- additional non-auto trait + | ---- first non-auto trait LL | trait _1 = _0; - | -- referenced here (additional use) + | -- first non-auto trait comes from this alias ... LL | trait _5 = Sync + ObjB + Send; - | ---- first non-auto trait + | ---- additional non-auto trait ... LL | trait _9 = _5 + Sync; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias LL | trait _10 = Unpin + _9; - | -- referenced here (first use) + | -- second non-auto trait comes from this alias ... LL | type _T45 = dyn Sync + Send + _10 + _1; - | --- ^^ trait alias used in trait object type (additional use) + | ^^^ -- first non-auto trait comes from this alias | | - | trait alias used in trait object type (first use) + | second non-auto trait comes from this alias | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjB + ObjA {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: ObjA + ObjB {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error: aborting due to 28 previous errors diff --git a/tests/ui/traits/alias/object-fail.rs b/tests/ui/traits/alias/object-fail.rs index 5c753ff207c..9a1cbad53e7 100644 --- a/tests/ui/traits/alias/object-fail.rs +++ b/tests/ui/traits/alias/object-fail.rs @@ -5,7 +5,7 @@ trait IteratorAlias = Iterator; fn main() { let _: &dyn EqAlias = &123; - //~^ ERROR the trait `Eq` cannot be made into an object [E0038] + //~^ ERROR the trait alias `EqAlias` is not dyn compatible [E0038] let _: &dyn IteratorAlias = &vec![123].into_iter(); //~^ ERROR must be specified } diff --git a/tests/ui/traits/alias/object-fail.stderr b/tests/ui/traits/alias/object-fail.stderr index 1b89b87db9f..52ce79a4597 100644 --- a/tests/ui/traits/alias/object-fail.stderr +++ b/tests/ui/traits/alias/object-fail.stderr @@ -1,13 +1,19 @@ -error[E0038]: the trait `Eq` cannot be made into an object - --> $DIR/object-fail.rs:7:13 +error[E0038]: the trait alias `EqAlias` is not dyn compatible + --> $DIR/object-fail.rs:7:17 | LL | let _: &dyn EqAlias = &123; - | ^^^^^^^^^^^ `Eq` cannot be made into an object + | ^^^^^^^ `EqAlias` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $SRC_DIR/core/src/cmp.rs:LL:COL | - = note: the trait cannot be made into an object because it uses `Self` as a type parameter + = note: ...because it uses `Self` as a type parameter + | + ::: $DIR/object-fail.rs:3:7 + | +LL | trait EqAlias = Eq; + | ------- this trait is not dyn compatible... error[E0191]: the value of the associated type `Item` in `Iterator` must be specified --> $DIR/object-fail.rs:9:17 diff --git a/tests/ui/traits/alias/self-in-const-generics.rs b/tests/ui/traits/alias/self-in-const-generics.rs index b0de8ccd678..a7d0ac9cbb4 100644 --- a/tests/ui/traits/alias/self-in-const-generics.rs +++ b/tests/ui/traits/alias/self-in-const-generics.rs @@ -7,6 +7,6 @@ trait Bar<const N: usize> {} trait BB = Bar<{ 2 + 1 }>; fn foo(x: &dyn BB) {} -//~^ ERROR the trait alias `BB` cannot be made into an object [E0038] +//~^ ERROR the trait alias `BB` is not dyn compatible [E0038] fn main() {} diff --git a/tests/ui/traits/alias/self-in-const-generics.stderr b/tests/ui/traits/alias/self-in-const-generics.stderr index 3de31b64c8b..3c799492591 100644 --- a/tests/ui/traits/alias/self-in-const-generics.stderr +++ b/tests/ui/traits/alias/self-in-const-generics.stderr @@ -1,10 +1,21 @@ -error[E0038]: the trait alias `BB` cannot be made into an object +error[E0038]: the trait alias `BB` is not dyn compatible --> $DIR/self-in-const-generics.rs:9:16 | LL | fn foo(x: &dyn BB) {} - | ^^ + | ^^ `BB` is not dyn compatible | - = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/self-in-const-generics.rs:7:12 + | +LL | trait BB = Bar<{ 2 + 1 }>; + | -- ^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter + | | + | this trait is not dyn compatible... +help: consider using an opaque type instead + | +LL | fn foo(x: &impl BB) {} + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/traits/alias/self-in-generics.rs b/tests/ui/traits/alias/self-in-generics.rs index 433b741532d..53752d9cede 100644 --- a/tests/ui/traits/alias/self-in-generics.rs +++ b/tests/ui/traits/alias/self-in-generics.rs @@ -6,6 +6,6 @@ pub trait SelfInput = Fn(&mut Self); pub fn f(_f: &dyn SelfInput) {} -//~^ ERROR the trait alias `SelfInput` cannot be made into an object [E0038] +//~^ ERROR the trait alias `SelfInput` is not dyn compatible [E0038] fn main() {} diff --git a/tests/ui/traits/alias/self-in-generics.stderr b/tests/ui/traits/alias/self-in-generics.stderr index ffc0a00ad7d..5639b2b44a1 100644 --- a/tests/ui/traits/alias/self-in-generics.stderr +++ b/tests/ui/traits/alias/self-in-generics.stderr @@ -1,10 +1,23 @@ -error[E0038]: the trait alias `SelfInput` cannot be made into an object +error[E0038]: the trait alias `SelfInput` is not dyn compatible --> $DIR/self-in-generics.rs:8:19 | LL | pub fn f(_f: &dyn SelfInput) {} - | ^^^^^^^^^ + | ^^^^^^^^^ `SelfInput` is not dyn compatible | - = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $DIR/self-in-generics.rs:6:23 + | +LL | pub trait SelfInput = Fn(&mut Self); + | --------- ^^^^^^^^^^^^^ + | | | + | | ...because it uses `Self` as a type parameter + | | ...because it uses `Self` as a type parameter + | this trait is not dyn compatible... +help: consider using an opaque type instead + | +LL | pub fn f(_f: &impl SelfInput) {} + | ~~~~ error: aborting due to 1 previous error diff --git a/tests/ui/traits/bad-sized.stderr b/tests/ui/traits/bad-sized.stderr index 0e82867ef03..21718cf0951 100644 --- a/tests/ui/traits/bad-sized.stderr +++ b/tests/ui/traits/bad-sized.stderr @@ -1,12 +1,12 @@ error[E0225]: only auto traits can be used as additional traits in a trait object - --> $DIR/bad-sized.rs:4:28 + --> $DIR/bad-sized.rs:4:20 | LL | let x: Vec<dyn Trait + Sized> = Vec::new(); - | ----- ^^^^^ additional non-auto trait + | ^^^^^ ----- first non-auto trait | | - | first non-auto trait + | additional non-auto trait | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Trait + Sized {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Sized + Trait {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error: aborting due to 1 previous error diff --git a/tests/ui/traits/issue-20692.rs b/tests/ui/traits/issue-20692.rs index 1cb2d8c7302..10611a232f7 100644 --- a/tests/ui/traits/issue-20692.rs +++ b/tests/ui/traits/issue-20692.rs @@ -2,10 +2,10 @@ trait Array: Sized + Copy {} fn f<T: Array>(x: &T) { let _ = x - //~^ ERROR `Array` cannot be made into an object + //~^ ERROR `Array` is not dyn compatible as &dyn Array; - //~^ ERROR `Array` cannot be made into an object + //~^ ERROR `Array` is not dyn compatible } fn main() {} diff --git a/tests/ui/traits/issue-20692.stderr b/tests/ui/traits/issue-20692.stderr index 5e6a967fdc4..50ea7cde961 100644 --- a/tests/ui/traits/issue-20692.stderr +++ b/tests/ui/traits/issue-20692.stderr @@ -1,32 +1,34 @@ -error[E0038]: the trait `Array` cannot be made into an object +error[E0038]: the trait `Array` is not dyn compatible --> $DIR/issue-20692.rs:7:5 | LL | &dyn Array; - | ^^^^^^^^^^ `Array` cannot be made into an object + | ^^^^^^^^^^ `Array` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-20692.rs:1:14 | LL | trait Array: Sized + Copy {} | ----- ^^^^^ ^^^^ ...because it requires `Self: Sized` | | | | | ...because it requires `Self: Sized` - | this trait cannot be made into an object... + | this trait is not dyn compatible... -error[E0038]: the trait `Array` cannot be made into an object +error[E0038]: the trait `Array` is not dyn compatible --> $DIR/issue-20692.rs:4:13 | LL | let _ = x - | ^ `Array` cannot be made into an object + | ^ `Array` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-20692.rs:1:14 | LL | trait Array: Sized + Copy {} | ----- ^^^^^ ^^^^ ...because it requires `Self: Sized` | | | | | ...because it requires `Self: Sized` - | this trait cannot be made into an object... + | this trait is not dyn compatible... = note: required for the cast from `&T` to `&dyn Array` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/issue-28576.rs b/tests/ui/traits/issue-28576.rs index e19bd263581..fd026044401 100644 --- a/tests/ui/traits/issue-28576.rs +++ b/tests/ui/traits/issue-28576.rs @@ -6,7 +6,7 @@ pub trait Bar: Foo<Assoc=()> { //~^ ERROR: the size for values of type `Self` cannot be known //~| ERROR: the size for values of type `Self` cannot be known fn new(&self, b: & - dyn Bar //~ ERROR the trait `Bar` cannot be made into an object + dyn Bar //~ ERROR the trait `Bar` is not dyn compatible <Assoc=()> ); } diff --git a/tests/ui/traits/issue-28576.stderr b/tests/ui/traits/issue-28576.stderr index 23581f2ee51..ba113d573d6 100644 --- a/tests/ui/traits/issue-28576.stderr +++ b/tests/ui/traits/issue-28576.stderr @@ -18,14 +18,16 @@ help: consider relaxing the implicit `Sized` restriction LL | pub trait Foo<RHS: ?Sized=Self> { | ++++++++ -error[E0038]: the trait `Bar` cannot be made into an object - --> $DIR/issue-28576.rs:9:12 +error[E0038]: the trait `Bar` is not dyn compatible + --> $DIR/issue-28576.rs:9:16 | -LL | / dyn Bar +LL | dyn Bar + | ________________^ LL | | <Assoc=()> - | |________________________^ `Bar` cannot be made into an object + | |________________________^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-28576.rs:5:16 | LL | pub trait Bar: Foo<Assoc=()> { @@ -33,7 +35,7 @@ LL | pub trait Bar: Foo<Assoc=()> { | | | | | | | ...because it uses `Self` as a type parameter | | ...because it uses `Self` as a type parameter - | this trait cannot be made into an object... + | this trait is not dyn compatible... help: consider using an opaque type instead | LL | impl Bar diff --git a/tests/ui/traits/issue-38404.rs b/tests/ui/traits/issue-38404.rs index 9b60116f733..36da594c015 100644 --- a/tests/ui/traits/issue-38404.rs +++ b/tests/ui/traits/issue-38404.rs @@ -1,8 +1,8 @@ trait A<T>: std::ops::Add<Self> + Sized {} trait B<T>: A<T> {} trait C<T>: A<dyn B<T, Output = usize>> {} -//~^ ERROR the trait `B` cannot be made into an object -//~| ERROR the trait `B` cannot be made into an object -//~| ERROR the trait `B` cannot be made into an object +//~^ ERROR the trait `B` is not dyn compatible +//~| ERROR the trait `B` is not dyn compatible +//~| ERROR the trait `B` is not dyn compatible fn main() {} diff --git a/tests/ui/traits/issue-38404.stderr b/tests/ui/traits/issue-38404.stderr index 145eeb88dd5..f9e592255dd 100644 --- a/tests/ui/traits/issue-38404.stderr +++ b/tests/ui/traits/issue-38404.stderr @@ -1,45 +1,48 @@ -error[E0038]: the trait `B` cannot be made into an object - --> $DIR/issue-38404.rs:3:15 +error[E0038]: the trait `B` is not dyn compatible + --> $DIR/issue-38404.rs:3:19 | LL | trait C<T>: A<dyn B<T, Output = usize>> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-38404.rs:1:13 | LL | trait A<T>: std::ops::Add<Self> + Sized {} | ^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter LL | trait B<T>: A<T> {} - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... -error[E0038]: the trait `B` cannot be made into an object - --> $DIR/issue-38404.rs:3:15 +error[E0038]: the trait `B` is not dyn compatible + --> $DIR/issue-38404.rs:3:19 | LL | trait C<T>: A<dyn B<T, Output = usize>> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-38404.rs:1:13 | LL | trait A<T>: std::ops::Add<Self> + Sized {} | ^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter LL | trait B<T>: A<T> {} - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error[E0038]: the trait `B` cannot be made into an object - --> $DIR/issue-38404.rs:3:15 +error[E0038]: the trait `B` is not dyn compatible + --> $DIR/issue-38404.rs:3:19 | LL | trait C<T>: A<dyn B<T, Output = usize>> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ `B` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^ `B` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-38404.rs:1:13 | LL | trait A<T>: std::ops::Add<Self> + Sized {} | ^^^^^^^^^^^^^^^^^^^ ...because it uses `Self` as a type parameter LL | trait B<T>: A<T> {} - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: aborting due to 3 previous errors diff --git a/tests/ui/traits/issue-38604.rs b/tests/ui/traits/issue-38604.rs index 002a3c43fcb..d90aa61ef9f 100644 --- a/tests/ui/traits/issue-38604.rs +++ b/tests/ui/traits/issue-38604.rs @@ -11,6 +11,6 @@ impl Foo for () { } fn main() { - let _f: Box<dyn Foo> = //~ ERROR `Foo` cannot be made into an object - Box::new(()); //~ ERROR `Foo` cannot be made into an object + let _f: Box<dyn Foo> = //~ ERROR `Foo` is not dyn compatible + Box::new(()); //~ ERROR `Foo` is not dyn compatible } diff --git a/tests/ui/traits/issue-38604.stderr b/tests/ui/traits/issue-38604.stderr index 5c788b0c85d..94f9c1540ad 100644 --- a/tests/ui/traits/issue-38604.stderr +++ b/tests/ui/traits/issue-38604.stderr @@ -1,32 +1,34 @@ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/issue-38604.rs:14:13 | LL | let _f: Box<dyn Foo> = - | ^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-38604.rs:2:22 | LL | trait Foo where u32: Q<Self> { | --- ^^^^^^^ ...because it uses `Self` as a type parameter | | - | this trait cannot be made into an object... - = help: only type `()` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `()` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/issue-38604.rs:15:9 | LL | Box::new(()); - | ^^^^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-38604.rs:2:22 | LL | trait Foo where u32: Q<Self> { | --- ^^^^^^^ ...because it uses `Self` as a type parameter | | - | this trait cannot be made into an object... - = help: only type `()` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `()` implements `Foo`; consider using it directly instead. = note: required for the cast from `Box<()>` to `Box<dyn Foo>` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/issue-72410.rs b/tests/ui/traits/issue-72410.rs index c95f1dfdca5..df3738e2730 100644 --- a/tests/ui/traits/issue-72410.rs +++ b/tests/ui/traits/issue-72410.rs @@ -12,7 +12,7 @@ pub trait Foo { pub trait Bar { fn map() where for<'a> &'a mut [dyn Bar]: ; - //~^ ERROR: the trait `Bar` cannot be made into an object + //~^ ERROR: the trait `Bar` is not dyn compatible } fn main() {} diff --git a/tests/ui/traits/issue-72410.stderr b/tests/ui/traits/issue-72410.stderr index 6d56a198fc1..002345bff84 100644 --- a/tests/ui/traits/issue-72410.stderr +++ b/tests/ui/traits/issue-72410.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `Bar` cannot be made into an object +error[E0038]: the trait `Bar` is not dyn compatible --> $DIR/issue-72410.rs:14:19 | LL | where for<'a> &'a mut [dyn Bar]: ; - | ^^^^^^^^^^^^^^^^^ `Bar` cannot be made into an object + | ^^^^^^^^^^^^^^^^^ `Bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-72410.rs:13:8 | LL | pub trait Bar { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn map() | ^^^ ...because associated function `map` has no `self` parameter help: consider turning `map` into a method by giving it a `&self` argument diff --git a/tests/ui/traits/item-privacy.rs b/tests/ui/traits/item-privacy.rs index a3e1a22e7a8..f5c741ccaa5 100644 --- a/tests/ui/traits/item-privacy.rs +++ b/tests/ui/traits/item-privacy.rs @@ -99,8 +99,8 @@ fn check_assoc_const() { S::C; // OK // A, B, C are resolved as inherent items, their traits don't need to be in scope <dyn C>::A; //~ ERROR associated constant `A` is private - //~^ ERROR the trait `assoc_const::C` cannot be made into an object - <dyn C>::B; // ERROR the trait `assoc_const::C` cannot be made into an object + //~^ ERROR the trait `assoc_const::C` is not dyn compatible + <dyn C>::B; // ERROR the trait `assoc_const::C` is not dyn compatible C::C; // OK } diff --git a/tests/ui/traits/item-privacy.stderr b/tests/ui/traits/item-privacy.stderr index c20d2f723c5..c97158a5b76 100644 --- a/tests/ui/traits/item-privacy.stderr +++ b/tests/ui/traits/item-privacy.stderr @@ -136,13 +136,14 @@ LL | const A: u8 = 0; LL | <dyn C>::A; | ^ private associated constant -error[E0038]: the trait `assoc_const::C` cannot be made into an object +error[E0038]: the trait `assoc_const::C` is not dyn compatible --> $DIR/item-privacy.rs:101:6 | LL | <dyn C>::A; - | ^^^^^ `assoc_const::C` cannot be made into an object + | ^^^^^ `assoc_const::C` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/item-privacy.rs:25:15 | LL | const A: u8 = 0; @@ -152,13 +153,13 @@ LL | const B: u8 = 0; | ^ ...because it contains this associated `const` ... LL | pub trait C: A + B { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | const C: u8 = 0; | ^ ...because it contains this associated `const` = help: consider moving `C` to another trait = help: consider moving `A` to another trait = help: consider moving `B` to another trait - = help: only type `S` implements the trait, consider using it directly instead + = help: only type `S` implements `assoc_const::C`; consider using it directly instead. error[E0223]: ambiguous associated type --> $DIR/item-privacy.rs:115:12 diff --git a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr index 541b49b024f..682d18842b8 100644 --- a/tests/ui/traits/missing-for-type-in-impl.e2015.stderr +++ b/tests/ui/traits/missing-for-type-in-impl.e2015.stderr @@ -34,17 +34,18 @@ help: you might have intended to implement this trait for a given type LL | impl Foo<i64> for /* Type */ { | ++++++++++++++ -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/missing-for-type-in-impl.rs:8:6 | LL | impl Foo<i64> { - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/missing-for-type-in-impl.rs:4:8 | LL | trait Foo<T> { - | --- this trait cannot be made into an object... + | --- this trait is not dyn compatible... LL | fn id(me: T) -> T; | ^^ ...because associated function `id` has no `self` parameter help: consider turning `id` into a method by giving it a `&self` argument diff --git a/tests/ui/traits/missing-for-type-in-impl.rs b/tests/ui/traits/missing-for-type-in-impl.rs index e5dd3651609..e8163954274 100644 --- a/tests/ui/traits/missing-for-type-in-impl.rs +++ b/tests/ui/traits/missing-for-type-in-impl.rs @@ -11,7 +11,7 @@ impl Foo<i64> { //[e2015]~| WARNING trait objects without an explicit `dyn` are deprecated //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! -//[e2015]~| ERROR the trait `Foo` cannot be made into an object +//[e2015]~| ERROR the trait `Foo` is not dyn compatible fn id(me: i64) -> i64 {me} } diff --git a/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs new file mode 100644 index 00000000000..5cea9bb74d7 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.rs @@ -0,0 +1,28 @@ +//@ compile-flags: -Znext-solver + +// When encountering a fulfillment error from an `alias-relate` goal failing, we +// would previously manually construct a `normalizes-to` goal involving the alias +// and an infer var. This would then ICE as normalization would return a nested +// goal (the `T: Sized` from the `Trait` impl for `Foo<T>` below) from the root goal +// which is not supported. + +struct Foo<T>(T); + +trait Trait { + type Assoc; +} + +// `T: Sized` being explicit is not required, but the bound being present *is*. +impl<T: Sized> Trait for Foo<T> { + type Assoc = u64; +} + +fn bar<T: Trait<Assoc = u32>>(_: T) {} + +fn main() { + let foo = Foo(Default::default()); + bar(foo); + //~^ ERROR: type mismatch resolving `<Foo<_> as Trait>::Assoc == u32` + // Here diagnostics would manually construct a `<Foo<?y> as Trait>::Assoc normalizes-to ?x` goal + // which would return a nested goal of `?y: Sized` from the impl. +} diff --git a/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.stderr b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.stderr new file mode 100644 index 00000000000..ff3cbdb2c78 --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/alias_relate_error_uses_structurally_normalize.stderr @@ -0,0 +1,17 @@ +error[E0271]: type mismatch resolving `<Foo<_> as Trait>::Assoc == u32` + --> $DIR/alias_relate_error_uses_structurally_normalize.rs:24:9 + | +LL | bar(foo); + | --- ^^^ expected `u32`, found `u64` + | | + | required by a bound introduced by this call + | +note: required by a bound in `bar` + --> $DIR/alias_relate_error_uses_structurally_normalize.rs:20:17 + | +LL | fn bar<T: Trait<Assoc = u32>>(_: T) {} + | ^^^^^^^^^^^ required by this bound in `bar` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr new file mode 100644 index 00000000000..a863886181c --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.current.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `Foo: Trait` is not satisfied + --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:24:20 + | +LL | requires_trait(Foo); + | -------------- ^^^ the trait `Trait` is not implemented for `Foo` + | | + | required by a bound introduced by this call + | +note: required by a bound in `requires_trait` + --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:19:22 + | +LL | fn requires_trait<T: Trait>(_: T) {} + | ^^^^^ required by this bound in `requires_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr new file mode 100644 index 00000000000..a863886181c --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.next.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `Foo: Trait` is not satisfied + --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:24:20 + | +LL | requires_trait(Foo); + | -------------- ^^^ the trait `Trait` is not implemented for `Foo` + | | + | required by a bound introduced by this call + | +note: required by a bound in `requires_trait` + --> $DIR/dont-pick-fnptr-bound-as-leaf.rs:19:22 + | +LL | fn requires_trait<T: Trait>(_: T) {} + | ^^^^^ required by this bound in `requires_trait` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs new file mode 100644 index 00000000000..995f2c9fbee --- /dev/null +++ b/tests/ui/traits/next-solver/diagnostics/dont-pick-fnptr-bound-as-leaf.rs @@ -0,0 +1,28 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +// When emitting an error for `Foo: Trait` not holding we attempt to find a nested goal +// to give as the reason why the bound does not hold. This test checks that we do not +// try to tell the user that `Foo: FnPtr` is unimplemented as that would be confusing. + +#![feature(fn_ptr_trait)] + +use std::marker::FnPtr; + +trait Trait {} + +impl<T: FnPtr> Trait for T {} + +struct Foo; + +fn requires_trait<T: Trait>(_: T) {} +//~^ NOTE: required by a bound in `requires_trait` +//~| NOTE: required by this bound in `requires_trait` + +fn main() { + requires_trait(Foo); + //~^ ERROR: the trait bound `Foo: Trait` is not satisfied + //~| NOTE: the trait `Trait` is not implemented for `Foo` + //~| NOTE: required by a bound introduced by this call +} diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs new file mode 100644 index 00000000000..d05def2cb75 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.rs @@ -0,0 +1,17 @@ +//@ compile-flags: -Znext-solver + +trait Wf { + type Assoc; +} + +struct S { + f: &'static <() as Wf>::Assoc, + //~^ ERROR the trait bound `(): Wf` is not satisfied +} + +fn main() { + let x: S = todo!(); + let y: &() = x.f; + //~^ ERROR mismatched types + //~| ERROR the trait bound `(): Wf` is not satisfied +} diff --git a/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr new file mode 100644 index 00000000000..32a7766a638 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-in-coerce-pointers.stderr @@ -0,0 +1,39 @@ +error[E0277]: the trait bound `(): Wf` is not satisfied + --> $DIR/non-wf-in-coerce-pointers.rs:8:17 + | +LL | f: &'static <() as Wf>::Assoc, + | ^^^^^^^^^^^^^^^^^ the trait `Wf` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/non-wf-in-coerce-pointers.rs:3:1 + | +LL | trait Wf { + | ^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/non-wf-in-coerce-pointers.rs:14:18 + | +LL | let y: &() = x.f; + | --- ^^^ types differ + | | + | expected due to this + | + = note: expected reference `&()` + found reference `&'static <() as Wf>::Assoc` + +error[E0277]: the trait bound `(): Wf` is not satisfied + --> $DIR/non-wf-in-coerce-pointers.rs:14:18 + | +LL | let y: &() = x.f; + | ^^^ the trait `Wf` is not implemented for `()` + | +help: this trait has no implementations, consider adding one + --> $DIR/non-wf-in-coerce-pointers.rs:3:1 + | +LL | trait Wf { + | ^^^^^^^^ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs b/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs new file mode 100644 index 00000000000..dc96652f82f --- /dev/null +++ b/tests/ui/traits/next-solver/normalization-shadowing/global-trait-with-project.rs @@ -0,0 +1,21 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// `(): Trait` is a global where-bound with a projection bound. +// This previously resulted in ambiguity as we considered both +// the impl and the where-bound while normalizing. + +trait Trait { + type Assoc; +} +impl Trait for () { + type Assoc = &'static (); +} + +fn foo<'a>(x: <() as Trait>::Assoc) +where + (): Trait<Assoc = &'a ()>, +{ +} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs index a635edb4485..28785ae3dea 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs +++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.rs @@ -17,8 +17,8 @@ impl<T: ?Sized> Bar<T> for () {} fn main() { let x: &dyn Foo = &(); - //~^ ERROR the trait `Foo` cannot be made into an object - //~| ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible + //~| ERROR the trait `Foo` is not dyn compatible needs_bar(x); - //~^ ERROR the trait `Foo` cannot be made into an object + //~^ ERROR the trait `Foo` is not dyn compatible } diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr index dd2dca74f90..8448890c084 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr +++ b/tests/ui/traits/non_lifetime_binders/supertrait-dyn-compatibility.stderr @@ -7,51 +7,54 @@ LL | #![feature(non_lifetime_binders)] = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information = note: `#[warn(incomplete_features)]` on by default -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/supertrait-dyn-compatibility.rs:19:23 | LL | let x: &dyn Foo = &(); - | ^^^ `Foo` cannot be made into an object + | ^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables | | - | this trait cannot be made into an object... - = help: only type `()` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `()` implements `Foo`; consider using it directly instead. = note: required for the cast from `&()` to `&dyn Foo` -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/supertrait-dyn-compatibility.rs:19:12 | LL | let x: &dyn Foo = &(); - | ^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables | | - | this trait cannot be made into an object... - = help: only type `()` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `()` implements `Foo`; consider using it directly instead. -error[E0038]: the trait `Foo` cannot be made into an object +error[E0038]: the trait `Foo` is not dyn compatible --> $DIR/supertrait-dyn-compatibility.rs:22:5 | LL | needs_bar(x); - | ^^^^^^^^^ `Foo` cannot be made into an object + | ^^^^^^^^^ `Foo` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/supertrait-dyn-compatibility.rs:4:12 | LL | trait Foo: for<T> Bar<T> {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables | | - | this trait cannot be made into an object... - = help: only type `()` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `()` implements `Foo`; consider using it directly instead. error: aborting due to 3 previous errors; 1 warning emitted diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs index 4aadd45c49c..6dcfc754448 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.rs @@ -8,9 +8,8 @@ trait Try { fn w<'a, T: 'a, F: Fn(&'a T)>() { let b: &dyn FromResidual = &(); - //~^ ERROR: the trait `FromResidual` cannot be made into an object - //~| ERROR: the trait `FromResidual` cannot be made into an object - //~| ERROR: the trait `FromResidual` cannot be made into an object + //~^ ERROR: the trait `FromResidual` is not dyn compatible + //~| ERROR: the trait `FromResidual` is not dyn compatible } fn main() {} diff --git a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr index c67a8c05379..7040c067f5c 100644 --- a/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr +++ b/tests/ui/traits/object/canonicalize-fresh-infer-vars-issue-103626.stderr @@ -1,22 +1,15 @@ -error[E0038]: the trait `FromResidual` cannot be made into an object - --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:17 - | -LL | let b: &dyn FromResidual = &(); - | ^^^^^^^^^^^^ - | - = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause - -error[E0038]: the trait `FromResidual` cannot be made into an object +error[E0038]: the trait `FromResidual` is not dyn compatible --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:32 | LL | let b: &dyn FromResidual = &(); - | ^^^ `FromResidual` cannot be made into an object + | ^^^ `FromResidual` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 | LL | trait FromResidual<R = <Self as Try>::Residual> { - | ------------ this trait cannot be made into an object... + | ------------ this trait is not dyn compatible... LL | fn from_residual(residual: R) -> Self; | ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter = note: required for the cast from `&()` to `&dyn FromResidual<{type error}>` @@ -29,17 +22,18 @@ help: alternatively, consider constraining `from_residual` so it does not apply LL | fn from_residual(residual: R) -> Self where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `FromResidual` cannot be made into an object +error[E0038]: the trait `FromResidual` is not dyn compatible --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:10:12 | LL | let b: &dyn FromResidual = &(); - | ^^^^^^^^^^^^^^^^^ `FromResidual` cannot be made into an object + | ^^^^^^^^^^^^^^^^^ `FromResidual` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/canonicalize-fresh-infer-vars-issue-103626.rs:2:8 | LL | trait FromResidual<R = <Self as Try>::Residual> { - | ------------ this trait cannot be made into an object... + | ------------ this trait is not dyn compatible... LL | fn from_residual(residual: R) -> Self; | ^^^^^^^^^^^^^ ...because associated function `from_residual` has no `self` parameter help: consider turning `from_residual` into a method by giving it a `&self` argument @@ -51,6 +45,6 @@ help: alternatively, consider constraining `from_residual` so it does not apply LL | fn from_residual(residual: R) -> Self where Self: Sized; | +++++++++++++++++ -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/traits/object/macro-matcher.rs b/tests/ui/traits/object/macro-matcher.rs index 91097874997..675d9f51532 100644 --- a/tests/ui/traits/object/macro-matcher.rs +++ b/tests/ui/traits/object/macro-matcher.rs @@ -6,7 +6,7 @@ macro_rules! m { fn main() { m!(dyn Copy + Send + 'static); - //~^ ERROR the trait `Copy` cannot be made into an object + //~^ ERROR the trait `Copy` is not dyn compatible m!(dyn 'static + Send); m!(dyn 'static +); //~ ERROR at least one trait is required for an object type } diff --git a/tests/ui/traits/object/macro-matcher.stderr b/tests/ui/traits/object/macro-matcher.stderr index 7924c86e294..ab0fc213c9f 100644 --- a/tests/ui/traits/object/macro-matcher.stderr +++ b/tests/ui/traits/object/macro-matcher.stderr @@ -4,14 +4,15 @@ error[E0224]: at least one trait is required for an object type LL | m!(dyn 'static +); | ^^^^^^^^^^^^^ -error[E0038]: the trait `Copy` cannot be made into an object +error[E0038]: the trait `Copy` is not dyn compatible --> $DIR/macro-matcher.rs:8:8 | LL | m!(dyn Copy + Send + 'static); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^ `Copy` is not dyn compatible | - = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "dyn-compatible" 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> + = note: the trait is not dyn compatible because it requires `Self: Sized` + = note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> error: aborting due to 2 previous errors diff --git a/tests/ui/traits/object/safety.stderr b/tests/ui/traits/object/safety.stderr index a2cb656b08d..eab59f39c28 100644 --- a/tests/ui/traits/object/safety.stderr +++ b/tests/ui/traits/object/safety.stderr @@ -1,17 +1,18 @@ -error[E0038]: the trait `Tr` cannot be made into an object +error[E0038]: the trait `Tr` is not dyn compatible --> $DIR/safety.rs:15:22 | LL | let _: &dyn Tr = &St; - | ^^^ `Tr` cannot be made into an object + | ^^^ `Tr` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/safety.rs:4:8 | LL | trait Tr { - | -- this trait cannot be made into an object... + | -- this trait is not dyn compatible... LL | fn foo(); | ^^^ ...because associated function `foo` has no `self` parameter - = help: only type `St` implements the trait, consider using it directly instead + = help: only type `St` implements `Tr`; consider using it directly instead. = note: required for the cast from `&St` to `&dyn Tr` help: consider turning `foo` into a method by giving it a `&self` argument | @@ -22,20 +23,21 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o LL | fn foo() where Self: Sized; | +++++++++++++++++ -error[E0038]: the trait `Tr` cannot be made into an object +error[E0038]: the trait `Tr` is not dyn compatible --> $DIR/safety.rs:15:12 | LL | let _: &dyn Tr = &St; - | ^^^^^^^ `Tr` cannot be made into an object + | ^^^^^^^ `Tr` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/safety.rs:4:8 | LL | trait Tr { - | -- this trait cannot be made into an object... + | -- this trait is not dyn compatible... LL | fn foo(); | ^^^ ...because associated function `foo` has no `self` parameter - = help: only type `St` implements the trait, consider using it directly instead + = help: only type `St` implements `Tr`; consider using it directly instead. help: consider turning `foo` into a method by giving it a `&self` argument | LL | fn foo(&self); diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr index 3da95b47844..8915e490b4d 100644 --- a/tests/ui/traits/test-2.stderr +++ b/tests/ui/traits/test-2.stderr @@ -26,65 +26,74 @@ note: method defined here, with 1 generic parameter: `X` LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); } | ^^^^ - -error[E0038]: the trait `bar` cannot be made into an object +error[E0038]: the trait `bar` is not dyn compatible --> $DIR/test-2.rs:13:22 | LL | (Box::new(10) as Box<dyn bar>).dup(); - | ^^^^^^^^^^^^ `bar` cannot be made into an object + | ^^^^^^^^^^^^ `bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/test-2.rs:4:30 | LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); } | --- ^^^^ ^^^^ ...because method `blah` has generic type parameters | | | | | ...because method `dup` references the `Self` type in its return type - | this trait cannot be made into an object... + | this trait is not dyn compatible... = help: consider moving `dup` to another trait = help: consider moving `blah` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `bar` for this new enum and using it instead: + = help: the following types implement `bar`: i32 u32 + consider defining an enum where each variant holds one of these types, + implementing `bar` for this new enum and using it instead -error[E0038]: the trait `bar` cannot be made into an object +error[E0038]: the trait `bar` is not dyn compatible --> $DIR/test-2.rs:13:5 | LL | (Box::new(10) as Box<dyn bar>).dup(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/test-2.rs:4:30 | LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); } | --- ^^^^ ^^^^ ...because method `blah` has generic type parameters | | | | | ...because method `dup` references the `Self` type in its return type - | this trait cannot be made into an object... + | this trait is not dyn compatible... = help: consider moving `dup` to another trait = help: consider moving `blah` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `bar` for this new enum and using it instead: + = help: the following types implement `bar`: i32 u32 + consider defining an enum where each variant holds one of these types, + implementing `bar` for this new enum and using it instead -error[E0038]: the trait `bar` cannot be made into an object +error[E0038]: the trait `bar` is not dyn compatible --> $DIR/test-2.rs:13:6 | LL | (Box::new(10) as Box<dyn bar>).dup(); - | ^^^^^^^^^^^^ `bar` cannot be made into an object + | ^^^^^^^^^^^^ `bar` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/test-2.rs:4:30 | LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); } | --- ^^^^ ^^^^ ...because method `blah` has generic type parameters | | | | | ...because method `dup` references the `Self` type in its return type - | this trait cannot be made into an object... + | this trait is not dyn compatible... = help: consider moving `dup` to another trait = help: consider moving `blah` to another trait - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `bar` for this new enum and using it instead: + = help: the following types implement `bar`: i32 u32 + consider defining an enum where each variant holds one of these types, + implementing `bar` for this new enum and using it instead = note: required for the cast from `Box<{integer}>` to `Box<dyn bar>` error: aborting due to 5 previous errors diff --git a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr index 2d5bcf1fbc4..71717c6945e 100644 --- a/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr +++ b/tests/ui/type/type-parameter-defaults-referencing-Self-ppaux.stderr @@ -10,21 +10,20 @@ help: consider using a box or reference as appropriate LL | let y = x as dyn MyAdd<i32>; | ^ -error[E0038]: the trait `MyAdd` cannot be made into an object +error[E0038]: the trait `MyAdd` is not dyn compatible --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:14:18 | LL | let y = x as dyn MyAdd<i32>; - | ^^^^^^^^^^^^^^ `MyAdd` cannot be made into an object + | ^^^^^^^^^^^^^^ `MyAdd` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/type-parameter-defaults-referencing-Self-ppaux.rs:6:55 | LL | trait MyAdd<Rhs=Self> { fn add(&self, other: &Rhs) -> Self; } - | ----- ^^^^ ...because method `add` references the `Self` type in its return type - | | - | this trait cannot be made into an object... + | ----- this trait is not dyn compatible... ^^^^ ...because method `add` references the `Self` type in its return type = help: consider moving `add` to another trait - = help: only type `i32` implements the trait, consider using it directly instead + = help: only type `i32` implements `MyAdd`; consider using it directly instead. error: aborting due to 2 previous errors diff --git a/tests/ui/typeck/bad-index-due-to-nested.stderr b/tests/ui/typeck/bad-index-due-to-nested.current.stderr index dd2ce092368..dc3d998c399 100644 --- a/tests/ui/typeck/bad-index-due-to-nested.stderr +++ b/tests/ui/typeck/bad-index-due-to-nested.current.stderr @@ -1,11 +1,11 @@ error[E0277]: the trait bound `K: Hash` is not satisfied - --> $DIR/bad-index-due-to-nested.rs:20:5 + --> $DIR/bad-index-due-to-nested.rs:24:5 | LL | map[k] | ^^^ the trait `Hash` is not implemented for `K` | note: required for `HashMap<K, V>` to implement `Index<&K>` - --> $DIR/bad-index-due-to-nested.rs:7:12 + --> $DIR/bad-index-due-to-nested.rs:11:12 | LL | impl<K, V> Index<&K> for HashMap<K, V> | ^^^^^^^^^ ^^^^^^^^^^^^^ @@ -18,13 +18,13 @@ LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V | +++++++++++++++++ error[E0277]: the trait bound `V: Copy` is not satisfied - --> $DIR/bad-index-due-to-nested.rs:20:5 + --> $DIR/bad-index-due-to-nested.rs:24:5 | LL | map[k] | ^^^ the trait `Copy` is not implemented for `V` | note: required for `HashMap<K, V>` to implement `Index<&K>` - --> $DIR/bad-index-due-to-nested.rs:7:12 + --> $DIR/bad-index-due-to-nested.rs:11:12 | LL | impl<K, V> Index<&K> for HashMap<K, V> | ^^^^^^^^^ ^^^^^^^^^^^^^ @@ -37,7 +37,7 @@ LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a | +++++++++++++++++++ error[E0308]: mismatched types - --> $DIR/bad-index-due-to-nested.rs:20:9 + --> $DIR/bad-index-due-to-nested.rs:24:9 | LL | fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V { | - found this type parameter @@ -52,7 +52,7 @@ LL | map[&k] | + error[E0308]: mismatched types - --> $DIR/bad-index-due-to-nested.rs:20:5 + --> $DIR/bad-index-due-to-nested.rs:24:5 | LL | fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V { | - found this type parameter ----- expected `&'a V` because of return type diff --git a/tests/ui/typeck/bad-index-due-to-nested.next.stderr b/tests/ui/typeck/bad-index-due-to-nested.next.stderr new file mode 100644 index 00000000000..a0b275b7852 --- /dev/null +++ b/tests/ui/typeck/bad-index-due-to-nested.next.stderr @@ -0,0 +1,76 @@ +error[E0277]: the trait bound `K: Hash` is not satisfied + --> $DIR/bad-index-due-to-nested.rs:24:5 + | +LL | map[k] + | ^^^ the trait `Hash` is not implemented for `K` + | +note: required for `HashMap<K, V>` to implement `Index<&K>` + --> $DIR/bad-index-due-to-nested.rs:11:12 + | +LL | impl<K, V> Index<&K> for HashMap<K, V> + | ^^^^^^^^^ ^^^^^^^^^^^^^ +LL | where +LL | K: Hash, + | ---- unsatisfied trait bound introduced here +help: consider restricting type parameter `K` with trait `Hash` + | +LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V { + | +++++++++++++++++ + +error[E0277]: the trait bound `V: Copy` is not satisfied + --> $DIR/bad-index-due-to-nested.rs:24:5 + | +LL | map[k] + | ^^^ the trait `Copy` is not implemented for `V` + | +note: required for `HashMap<K, V>` to implement `Index<&K>` + --> $DIR/bad-index-due-to-nested.rs:11:12 + | +LL | impl<K, V> Index<&K> for HashMap<K, V> + | ^^^^^^^^^ ^^^^^^^^^^^^^ +... +LL | V: Copy, + | ---- unsatisfied trait bound introduced here +help: consider restricting type parameter `V` with trait `Copy` + | +LL | fn index<'a, K, V: std::marker::Copy>(map: &'a HashMap<K, V>, k: K) -> &'a V { + | +++++++++++++++++++ + +error[E0308]: mismatched types + --> $DIR/bad-index-due-to-nested.rs:24:9 + | +LL | fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V { + | - found this type parameter +LL | map[k] + | ^ expected `&K`, found type parameter `K` + | + = note: expected reference `&_` + found type parameter `_` +help: consider borrowing here + | +LL | map[&k] + | + + +error[E0277]: the trait bound `K: Hash` is not satisfied + --> $DIR/bad-index-due-to-nested.rs:24:5 + | +LL | map[k] + | ^^^^^^ the trait `Hash` is not implemented for `K` + | +note: required for `HashMap<K, V>` to implement `Index<&K>` + --> $DIR/bad-index-due-to-nested.rs:11:12 + | +LL | impl<K, V> Index<&K> for HashMap<K, V> + | ^^^^^^^^^ ^^^^^^^^^^^^^ +LL | where +LL | K: Hash, + | ---- unsatisfied trait bound introduced here +help: consider restricting type parameter `K` with trait `Hash` + | +LL | fn index<'a, K: std::hash::Hash, V>(map: &'a HashMap<K, V>, k: K) -> &'a V { + | +++++++++++++++++ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/bad-index-due-to-nested.rs b/tests/ui/typeck/bad-index-due-to-nested.rs index 2564b530004..e7f385865af 100644 --- a/tests/ui/typeck/bad-index-due-to-nested.rs +++ b/tests/ui/typeck/bad-index-due-to-nested.rs @@ -1,3 +1,7 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + use std::hash::Hash; use std::marker::PhantomData; use std::ops::Index; @@ -21,7 +25,8 @@ fn index<'a, K, V>(map: &'a HashMap<K, V>, k: K) -> &'a V { //~^ ERROR the trait bound `K: Hash` is not satisfied //~| ERROR the trait bound `V: Copy` is not satisfied //~| ERROR mismatched types - //~| ERROR mismatched types + //[current]~| ERROR mismatched types + //[next]~^^^^^ ERROR the trait bound `K: Hash` is not satisfied } fn main() {} diff --git a/tests/ui/typeck/issue-82772.stderr b/tests/ui/typeck/issue-82772.stderr index 321143cb968..a314306137a 100644 --- a/tests/ui/typeck/issue-82772.stderr +++ b/tests/ui/typeck/issue-82772.stderr @@ -2,19 +2,19 @@ error[E0451]: field `0` of struct `Box` is private --> $DIR/issue-82772.rs:5:15 | LL | let Box { 0: _, .. }: Box<()>; - | ^^^^ private field + | ^ private field error[E0451]: field `1` of struct `Box` is private --> $DIR/issue-82772.rs:6:15 | LL | let Box { 1: _, .. }: Box<()>; - | ^^^^ private field + | ^ private field error[E0451]: field `1` of struct `ModPrivateStruct` is private --> $DIR/issue-82772.rs:7:28 | LL | let ModPrivateStruct { 1: _, .. } = ModPrivateStruct::default(); - | ^^^^ private field + | ^ private field error: aborting due to 3 previous errors diff --git a/tests/ui/union/union-derive-eq.stderr b/tests/ui/union/union-derive-eq.current.stderr index b068edd6d69..151ceebe1ba 100644 --- a/tests/ui/union/union-derive-eq.stderr +++ b/tests/ui/union/union-derive-eq.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied - --> $DIR/union-derive-eq.rs:13:5 + --> $DIR/union-derive-eq.rs:21:5 | LL | #[derive(Eq)] | -- in this derive macro expansion diff --git a/tests/ui/union/union-derive-eq.next.stderr b/tests/ui/union/union-derive-eq.next.stderr new file mode 100644 index 00000000000..3952b1f1284 --- /dev/null +++ b/tests/ui/union/union-derive-eq.next.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied + --> $DIR/union-derive-eq.rs:21:5 + | +LL | #[derive(Eq)] + | -- in this derive macro expansion +LL | union U2 { +LL | a: PartialEqNotEq, + | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq` + | + = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider annotating `PartialEqNotEq` with `#[derive(Eq)]` + | +LL + #[derive(Eq)] +LL | struct PartialEqNotEq; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/union/union-derive-eq.rs b/tests/ui/union/union-derive-eq.rs index e689f8c27d7..085262a72a1 100644 --- a/tests/ui/union/union-derive-eq.rs +++ b/tests/ui/union/union-derive-eq.rs @@ -1,9 +1,17 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + #[derive(Eq)] // OK union U1 { a: u8, } -impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } } +impl PartialEq for U1 { + fn eq(&self, rhs: &Self) -> bool { + true + } +} #[derive(PartialEq, Copy, Clone)] struct PartialEqNotEq; @@ -13,6 +21,10 @@ union U2 { a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: Eq` is not satisfied } -impl PartialEq for U2 { fn eq(&self, rhs: &Self) -> bool { true } } +impl PartialEq for U2 { + fn eq(&self, rhs: &Self) -> bool { + true + } +} fn main() {} diff --git a/tests/ui/unpretty/staged-api-invalid-path-108697.stderr b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr index 9c6d1a042d7..e68e19c4dc9 100644 --- a/tests/ui/unpretty/staged-api-invalid-path-108697.stderr +++ b/tests/ui/unpretty/staged-api-invalid-path-108697.stderr @@ -1,4 +1,4 @@ -error: couldn't read $DIR/lol: No such file or directory (os error 2) +error: couldn't read `$DIR/lol`: No such file or directory (os error 2) --> $DIR/staged-api-invalid-path-108697.rs:8:1 | LL | mod foo; diff --git a/tests/ui/use/use.rs b/tests/ui/use/use.rs index db031500a4a..25b8e529c43 100644 --- a/tests/ui/use/use.rs +++ b/tests/ui/use/use.rs @@ -3,7 +3,7 @@ #![allow(stable_features)] #![allow(unused_imports)] -#![feature(start, no_core, core)] +#![feature(no_core, core)] #![no_core] extern crate std; @@ -18,5 +18,4 @@ mod baz { pub use std::str as x; } -#[start] -pub fn start(_: isize, _: *const *const u8) -> isize { 0 } +fn main() {} diff --git a/tests/ui/wf/issue-87495.rs b/tests/ui/wf/issue-87495.rs index 5aab7431134..ce5c617bbbd 100644 --- a/tests/ui/wf/issue-87495.rs +++ b/tests/ui/wf/issue-87495.rs @@ -2,7 +2,7 @@ trait T { const CONST: (bool, dyn T); - //~^ ERROR: the trait `T` cannot be made into an object [E0038] + //~^ ERROR: the trait `T` is not dyn compatible [E0038] } fn main() {} diff --git a/tests/ui/wf/issue-87495.stderr b/tests/ui/wf/issue-87495.stderr index 5973fff3e00..7be327e61d1 100644 --- a/tests/ui/wf/issue-87495.stderr +++ b/tests/ui/wf/issue-87495.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `T` cannot be made into an object +error[E0038]: the trait `T` is not dyn compatible --> $DIR/issue-87495.rs:4:25 | LL | const CONST: (bool, dyn T); - | ^^^^^ `T` cannot be made into an object + | ^^^^^ `T` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/issue-87495.rs:4:11 | LL | trait T { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | const CONST: (bool, dyn T); | ^^^^^ ...because it contains this associated `const` = help: consider moving `CONST` to another trait diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr index 38426545bc8..0b7f4cd4362 100644 --- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr +++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj-box.stderr @@ -1,49 +1,52 @@ -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:16:33 | LL | let t_box: Box<dyn Trait> = Box::new(S); - | ^^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... - = help: only type `S` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `S` implements `Trait`; consider using it directly instead. = note: required for the cast from `Box<S>` to `Box<dyn Trait>` -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:17:15 | LL | takes_box(Box::new(S)); - | ^^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... - = help: only type `S` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `S` implements `Trait`; consider using it directly instead. = note: required for the cast from `Box<S>` to `Box<(dyn Trait + 'static)>` -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:15:5 | LL | Box::new(S) as Box<dyn Trait>; - | ^^^^^^^^^^^ `Trait` cannot be made into an object + | ^^^^^^^^^^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-convert-dyn-incompat-trait-obj-box.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... - = help: only type `S` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `S` implements `Trait`; consider using it directly instead. = note: required for the cast from `Box<S>` to `Box<dyn Trait>` error: aborting due to 3 previous errors diff --git a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr index 94259aa5b0a..3f50e1192cf 100644 --- a/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr +++ b/tests/ui/wf/wf-convert-dyn-incompat-trait-obj.stderr @@ -1,49 +1,52 @@ -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:16:25 | LL | let t: &dyn Trait = &S; - | ^^ `Trait` cannot be made into an object + | ^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... - = help: only type `S` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `S` implements `Trait`; consider using it directly instead. = note: required for the cast from `&S` to `&dyn Trait` -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:17:17 | LL | takes_trait(&S); - | ^^ `Trait` cannot be made into an object + | ^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... - = help: only type `S` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `S` implements `Trait`; consider using it directly instead. = note: required for the cast from `&S` to `&dyn Trait` -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:15:5 | LL | &S as &dyn Trait; - | ^^ `Trait` cannot be made into an object + | ^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-convert-dyn-incompat-trait-obj.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... - = help: only type `S` implements the trait, consider using it directly instead + | this trait is not dyn compatible... + = help: only type `S` implements `Trait`; consider using it directly instead. = note: required for the cast from `&S` to `&dyn Trait` error: aborting due to 3 previous errors diff --git a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr index 6cd4ebf8412..8f68f9c5b6b 100644 --- a/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr +++ b/tests/ui/wf/wf-dyn-incompat-trait-obj-match.stderr @@ -12,40 +12,46 @@ LL | | } = note: expected reference `&S` found reference `&R` -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/wf-dyn-incompat-trait-obj-match.rs:26:21 | LL | Some(()) => &S, - | ^^ `Trait` cannot be made into an object + | ^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Trait` for this new enum and using it instead: + | this trait is not dyn compatible... + = help: the following types implement `Trait`: S R + consider defining an enum where each variant holds one of these types, + implementing `Trait` for this new enum and using it instead = note: required for the cast from `&S` to `&dyn Trait` -error[E0038]: the trait `Trait` cannot be made into an object +error[E0038]: the trait `Trait` is not dyn compatible --> $DIR/wf-dyn-incompat-trait-obj-match.rs:27:17 | LL | None => &R, - | ^^ `Trait` cannot be made into an object + | ^^ `Trait` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-dyn-incompat-trait-obj-match.rs:6:14 | LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | - | this trait cannot be made into an object... - = help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `Trait` for this new enum and using it instead: + | this trait is not dyn compatible... + = help: the following types implement `Trait`: S R + consider defining an enum where each variant holds one of these types, + implementing `Trait` for this new enum and using it instead = note: required for the cast from `&R` to `&dyn Trait` error: aborting due to 3 previous errors diff --git a/tests/ui/wf/wf-dyn-incompatible.stderr b/tests/ui/wf/wf-dyn-incompatible.stderr index cf016b63c74..1803376aaa1 100644 --- a/tests/ui/wf/wf-dyn-incompatible.stderr +++ b/tests/ui/wf/wf-dyn-incompatible.stderr @@ -1,14 +1,15 @@ -error[E0038]: the trait `A` cannot be made into an object +error[E0038]: the trait `A` is not dyn compatible --> $DIR/wf-dyn-incompatible.rs:9:13 | LL | let _x: &dyn A; - | ^^^^^^ `A` cannot be made into an object + | ^^^^^^ `A` is not dyn compatible | -note: for a trait to be "dyn-compatible" 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> +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> --> $DIR/wf-dyn-incompatible.rs:5:23 | LL | trait A { - | - this trait cannot be made into an object... + | - this trait is not dyn compatible... LL | fn foo(&self, _x: &Self); | ^^^^^ ...because method `foo` references the `Self` type in this parameter = help: consider moving `foo` to another trait diff --git a/tests/ui/wf/wf-fn-where-clause.stderr b/tests/ui/wf/wf-fn-where-clause.stderr index 76671dedabf..d73376e9861 100644 --- a/tests/ui/wf/wf-fn-where-clause.stderr +++ b/tests/ui/wf/wf-fn-where-clause.stderr @@ -14,14 +14,15 @@ help: consider further restricting type parameter `U` with trait `Copy` LL | fn foo<T,U>() where T: ExtraCopy<U>, U: std::marker::Copy | ++++++++++++++++++++++ -error[E0038]: the trait `Copy` cannot be made into an object +error[E0038]: the trait `Copy` is not dyn compatible --> $DIR/wf-fn-where-clause.rs:12:16 | LL | fn bar() where Vec<dyn Copy>:, {} - | ^^^^^^^^^^^^^ `Copy` cannot be made into an object + | ^^^^^^^^^^^^^ `Copy` is not dyn compatible | - = note: the trait cannot be made into an object because it requires `Self: Sized` - = note: for a trait to be "dyn-compatible" 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> + = note: the trait is not dyn compatible because it requires `Self: Sized` + = note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time --> $DIR/wf-fn-where-clause.rs:12:16 diff --git a/tests/ui/wf/wf-trait-fn-arg.stderr b/tests/ui/wf/wf-trait-fn-arg.current.stderr index 8b35f36fa68..d5dd36fad6d 100644 --- a/tests/ui/wf/wf-trait-fn-arg.stderr +++ b/tests/ui/wf/wf-trait-fn-arg.current.stderr @@ -1,14 +1,14 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-fn-arg.rs:10:23 + --> $DIR/wf-trait-fn-arg.rs:16:23 | LL | fn bar(&self, x: &Bar<Self>); | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | note: required by a bound in `Bar` - --> $DIR/wf-trait-fn-arg.rs:7:14 + --> $DIR/wf-trait-fn-arg.rs:11:15 | -LL | struct Bar<T:Eq+?Sized> { value: Box<T> } - | ^^ required by this bound in `Bar` +LL | struct Bar<T: Eq + ?Sized> { + | ^^ required by this bound in `Bar` help: consider further restricting `Self` | LL | fn bar(&self, x: &Bar<Self>) where Self: Eq; diff --git a/tests/ui/wf/wf-trait-fn-arg.next.stderr b/tests/ui/wf/wf-trait-fn-arg.next.stderr new file mode 100644 index 00000000000..c55dc5c8a12 --- /dev/null +++ b/tests/ui/wf/wf-trait-fn-arg.next.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `Self: Eq` is not satisfied + --> $DIR/wf-trait-fn-arg.rs:16:23 + | +LL | fn bar(&self, x: &Bar<Self>); + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | fn bar(&self, x: &Bar<Self>) where Self: Eq; + | ++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/wf-trait-fn-arg.rs b/tests/ui/wf/wf-trait-fn-arg.rs index 0445699427e..13a5b32828d 100644 --- a/tests/ui/wf/wf-trait-fn-arg.rs +++ b/tests/ui/wf/wf-trait-fn-arg.rs @@ -1,16 +1,22 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + // Check that we test WF conditions for fn arguments in a trait definition. #![feature(rustc_attrs)] #![allow(dead_code)] #![allow(unused_variables)] -struct Bar<T:Eq+?Sized> { value: Box<T> } +struct Bar<T: Eq + ?Sized> { + value: Box<T>, +} trait Foo { fn bar(&self, x: &Bar<Self>); - //~^ ERROR E0277 - // - // Here, Eq ought to be implemented. + //~^ ERROR E0277 + // + // Here, Eq ought to be implemented. } -fn main() { } +fn main() {} diff --git a/tests/ui/wf/wf-trait-fn-ret.stderr b/tests/ui/wf/wf-trait-fn-ret.current.stderr index 3d70f04def2..0ad786c2fd5 100644 --- a/tests/ui/wf/wf-trait-fn-ret.stderr +++ b/tests/ui/wf/wf-trait-fn-ret.current.stderr @@ -1,14 +1,14 @@ error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-fn-ret.rs:10:23 + --> $DIR/wf-trait-fn-ret.rs:15:23 | LL | fn bar(&self) -> &Bar<Self>; | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | note: required by a bound in `Bar` - --> $DIR/wf-trait-fn-ret.rs:7:14 + --> $DIR/wf-trait-fn-ret.rs:10:15 | -LL | struct Bar<T:Eq+?Sized> { value: Box<T> } - | ^^ required by this bound in `Bar` +LL | struct Bar<T: Eq + ?Sized> { + | ^^ required by this bound in `Bar` help: consider further restricting `Self` | LL | fn bar(&self) -> &Bar<Self> where Self: Eq; diff --git a/tests/ui/wf/wf-trait-fn-ret.next.stderr b/tests/ui/wf/wf-trait-fn-ret.next.stderr new file mode 100644 index 00000000000..b3dca17672d --- /dev/null +++ b/tests/ui/wf/wf-trait-fn-ret.next.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `Self: Eq` is not satisfied + --> $DIR/wf-trait-fn-ret.rs:15:23 + | +LL | fn bar(&self) -> &Bar<Self>; + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | fn bar(&self) -> &Bar<Self> where Self: Eq; + | ++++++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/wf-trait-fn-ret.rs b/tests/ui/wf/wf-trait-fn-ret.rs index f49e4308770..c00f6dd10af 100644 --- a/tests/ui/wf/wf-trait-fn-ret.rs +++ b/tests/ui/wf/wf-trait-fn-ret.rs @@ -1,16 +1,21 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) // Check that we test WF conditions for fn return types in a trait definition. #![feature(rustc_attrs)] #![allow(dead_code)] #![allow(unused_variables)] -struct Bar<T:Eq+?Sized> { value: Box<T> } +struct Bar<T: Eq + ?Sized> { + value: Box<T>, +} trait Foo { fn bar(&self) -> &Bar<Self>; - //~^ ERROR E0277 - // - // Here, Eq ought to be implemented. + //~^ ERROR E0277 + // + // Here, Eq ought to be implemented. } -fn main() { } +fn main() {} diff --git a/tests/ui/wf/wf-trait-fn-where-clause.current.stderr b/tests/ui/wf/wf-trait-fn-where-clause.current.stderr new file mode 100644 index 00000000000..db5454d0f3c --- /dev/null +++ b/tests/ui/wf/wf-trait-fn-where-clause.current.stderr @@ -0,0 +1,19 @@ +error[E0277]: the trait bound `Self: Eq` is not satisfied + --> $DIR/wf-trait-fn-where-clause.rs:18:20 + | +LL | Bar<Self>: Copy; + | ^^^^ the trait `Eq` is not implemented for `Self` + | +note: required by a bound in `Bar` + --> $DIR/wf-trait-fn-where-clause.rs:10:15 + | +LL | struct Bar<T: Eq + ?Sized> { + | ^^ required by this bound in `Bar` +help: consider further restricting `Self` + | +LL | Bar<Self>: Copy, Self: Eq; + | ++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/wf-trait-fn-where-clause.next.stderr b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr new file mode 100644 index 00000000000..8c8a5fa3e70 --- /dev/null +++ b/tests/ui/wf/wf-trait-fn-where-clause.next.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `Self: Eq` is not satisfied + --> $DIR/wf-trait-fn-where-clause.rs:18:20 + | +LL | Bar<Self>: Copy; + | ^^^^ the trait `Eq` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | Bar<Self>: Copy, Self: Eq; + | ++++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/wf-trait-fn-where-clause.rs b/tests/ui/wf/wf-trait-fn-where-clause.rs index 1d2427ff981..9e36682e449 100644 --- a/tests/ui/wf/wf-trait-fn-where-clause.rs +++ b/tests/ui/wf/wf-trait-fn-where-clause.rs @@ -1,17 +1,24 @@ -// Check that we test WF conditions for fn where clauses in a trait definition. +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +// Check that we test WF conditions for fn where clauses in a trait definition. #![allow(dead_code)] #![allow(unused_variables)] -struct Bar<T:Eq+?Sized> { value: Box<T> } +struct Bar<T: Eq + ?Sized> { + value: Box<T>, +} trait Foo { - fn bar(&self) where Self: Sized, Bar<Self>: Copy; - //~^ ERROR E0277 - // - // Here, Eq ought to be implemented. + fn bar(&self) + where + Self: Sized, + Bar<Self>: Copy; + //~^ ERROR E0277 + // + // Here, Eq ought to be implemented. } - -fn main() { } +fn main() {} diff --git a/tests/ui/wf/wf-trait-fn-where-clause.stderr b/tests/ui/wf/wf-trait-fn-where-clause.stderr deleted file mode 100644 index 0ad3b58e7c7..00000000000 --- a/tests/ui/wf/wf-trait-fn-where-clause.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: the trait bound `Self: Eq` is not satisfied - --> $DIR/wf-trait-fn-where-clause.rs:10:49 - | -LL | fn bar(&self) where Self: Sized, Bar<Self>: Copy; - | ^^^^ the trait `Eq` is not implemented for `Self` - | -note: required by a bound in `Bar` - --> $DIR/wf-trait-fn-where-clause.rs:7:14 - | -LL | struct Bar<T:Eq+?Sized> { value: Box<T> } - | ^^ required by this bound in `Bar` -help: consider further restricting `Self` - | -LL | fn bar(&self) where Self: Sized, Bar<Self>: Copy, Self: Eq; - | ++++++++++ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/where-clauses/where-clauses-method-unsatisfied.stderr b/tests/ui/where-clauses/where-clauses-method-unsatisfied.current.stderr index 840df342ef9..d1de813a2d9 100644 --- a/tests/ui/where-clauses/where-clauses-method-unsatisfied.stderr +++ b/tests/ui/where-clauses/where-clauses-method-unsatisfied.current.stderr @@ -1,14 +1,17 @@ error[E0277]: the trait bound `Bar: Eq` is not satisfied - --> $DIR/where-clauses-method-unsatisfied.rs:18:7 + --> $DIR/where-clauses-method-unsatisfied.rs:24:7 | LL | x.equals(&x); | ^^^^^^ the trait `Eq` is not implemented for `Bar` | note: required by a bound in `Foo::<T>::equals` - --> $DIR/where-clauses-method-unsatisfied.rs:11:52 + --> $DIR/where-clauses-method-unsatisfied.rs:16:12 | -LL | fn equals(&self, u: &Foo<T>) -> bool where T : Eq { - | ^^ required by this bound in `Foo::<T>::equals` +LL | fn equals(&self, u: &Foo<T>) -> bool + | ------ required by a bound in this associated function +LL | where +LL | T: Eq, + | ^^ required by this bound in `Foo::<T>::equals` help: consider annotating `Bar` with `#[derive(Eq)]` | LL + #[derive(Eq)] diff --git a/tests/ui/where-clauses/where-clauses-method-unsatisfied.next.stderr b/tests/ui/where-clauses/where-clauses-method-unsatisfied.next.stderr new file mode 100644 index 00000000000..d1de813a2d9 --- /dev/null +++ b/tests/ui/where-clauses/where-clauses-method-unsatisfied.next.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `Bar: Eq` is not satisfied + --> $DIR/where-clauses-method-unsatisfied.rs:24:7 + | +LL | x.equals(&x); + | ^^^^^^ the trait `Eq` is not implemented for `Bar` + | +note: required by a bound in `Foo::<T>::equals` + --> $DIR/where-clauses-method-unsatisfied.rs:16:12 + | +LL | fn equals(&self, u: &Foo<T>) -> bool + | ------ required by a bound in this associated function +LL | where +LL | T: Eq, + | ^^ required by this bound in `Foo::<T>::equals` +help: consider annotating `Bar` with `#[derive(Eq)]` + | +LL + #[derive(Eq)] +LL | struct Bar; // does not implement Eq + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/where-clauses/where-clauses-method-unsatisfied.rs b/tests/ui/where-clauses/where-clauses-method-unsatisfied.rs index a8ae0296407..34e9d9b57d1 100644 --- a/tests/ui/where-clauses/where-clauses-method-unsatisfied.rs +++ b/tests/ui/where-clauses/where-clauses-method-unsatisfied.rs @@ -1,14 +1,20 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) // Test that a where clause attached to a method allows us to add // additional constraints to a parameter out of scope. struct Foo<T> { - value: T + value: T, } struct Bar; // does not implement Eq impl<T> Foo<T> { - fn equals(&self, u: &Foo<T>) -> bool where T : Eq { + fn equals(&self, u: &Foo<T>) -> bool + where + T: Eq, + { self.value == u.value } } diff --git a/tests/ui/where-clauses/where-clauses-unsatisfied.stderr b/tests/ui/where-clauses/where-clauses-unsatisfied.current.stderr index 205b82d49bf..485b9459ddd 100644 --- a/tests/ui/where-clauses/where-clauses-unsatisfied.stderr +++ b/tests/ui/where-clauses/where-clauses-unsatisfied.current.stderr @@ -1,14 +1,17 @@ error[E0277]: the trait bound `Struct: Eq` is not satisfied - --> $DIR/where-clauses-unsatisfied.rs:6:10 + --> $DIR/where-clauses-unsatisfied.rs:15:10 | LL | drop(equal(&Struct, &Struct)) | ^^^^^ the trait `Eq` is not implemented for `Struct` | note: required by a bound in `equal` - --> $DIR/where-clauses-unsatisfied.rs:1:45 + --> $DIR/where-clauses-unsatisfied.rs:7:8 | -LL | fn equal<T>(a: &T, b: &T) -> bool where T : Eq { a == b } - | ^^ required by this bound in `equal` +LL | fn equal<T>(a: &T, b: &T) -> bool + | ----- required by a bound in this function +LL | where +LL | T: Eq, + | ^^ required by this bound in `equal` help: consider annotating `Struct` with `#[derive(Eq)]` | LL + #[derive(Eq)] diff --git a/tests/ui/where-clauses/where-clauses-unsatisfied.next.stderr b/tests/ui/where-clauses/where-clauses-unsatisfied.next.stderr new file mode 100644 index 00000000000..485b9459ddd --- /dev/null +++ b/tests/ui/where-clauses/where-clauses-unsatisfied.next.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `Struct: Eq` is not satisfied + --> $DIR/where-clauses-unsatisfied.rs:15:10 + | +LL | drop(equal(&Struct, &Struct)) + | ^^^^^ the trait `Eq` is not implemented for `Struct` + | +note: required by a bound in `equal` + --> $DIR/where-clauses-unsatisfied.rs:7:8 + | +LL | fn equal<T>(a: &T, b: &T) -> bool + | ----- required by a bound in this function +LL | where +LL | T: Eq, + | ^^ required by this bound in `equal` +help: consider annotating `Struct` with `#[derive(Eq)]` + | +LL + #[derive(Eq)] +LL | struct Struct; + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/where-clauses/where-clauses-unsatisfied.rs b/tests/ui/where-clauses/where-clauses-unsatisfied.rs index 8b067d30a2a..48798e2a15d 100644 --- a/tests/ui/where-clauses/where-clauses-unsatisfied.rs +++ b/tests/ui/where-clauses/where-clauses-unsatisfied.rs @@ -1,4 +1,13 @@ -fn equal<T>(a: &T, b: &T) -> bool where T : Eq { a == b } +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) + +fn equal<T>(a: &T, b: &T) -> bool +where + T: Eq, +{ + a == b +} struct Struct; diff --git a/triagebot.toml b/triagebot.toml index 5ee52bbf435..4a09fe116a5 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1025,6 +1025,7 @@ users_on_vacation = [ "nnethercote", "spastorino", "workingjubilee", + "kobzol" ] [[assign.warn_non_default_branch.exceptions]] |
