diff options
454 files changed, 10310 insertions, 5730 deletions
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml index 03584aed08d..b137497594f 100644 --- a/.github/workflows/dependencies.yml +++ b/.github/workflows/dependencies.yml @@ -64,11 +64,17 @@ jobs: - name: cargo update # Remove first line that always just says "Updating crates.io index" run: cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log + - name: cargo update rustbook + run: | + echo -e "\nrustbook dependencies:" >> cargo_update.log + cargo update --manifest-path src/tools/rustbook 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log - name: upload Cargo.lock artifact for use in PR uses: actions/upload-artifact@v4 with: name: Cargo-lock - path: Cargo.lock + path: | + Cargo.lock + src/tools/rustbook/Cargo.lock retention-days: 1 - name: upload cargo-update log artifact for use in PR uses: actions/upload-artifact@v4 @@ -113,7 +119,7 @@ jobs: git config user.name github-actions git config user.email github-actions@github.com git switch --force-create cargo_update - git add ./Cargo.lock + git add ./Cargo.lock ./src/tools/rustbook/Cargo.lock git commit --no-verify --file=commit.txt - name: push diff --git a/.gitignore b/.gitignore index f1ca6a79b5c..87d02563ed0 100644 --- a/.gitignore +++ b/.gitignore @@ -50,7 +50,6 @@ build/ /target /src/bootstrap/target /src/tools/x/target -/inc-fat/ # Created by default with `src/ci/docker/run.sh` /obj/ /rustc-ice* diff --git a/.reuse/dep5 b/.reuse/dep5 deleted file mode 100644 index 5706ea0b204..00000000000 --- a/.reuse/dep5 +++ /dev/null @@ -1,124 +0,0 @@ -# WARNING: this metadata is currently incomplete, do not rely on it yet. - -Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ - -# Note that we're explicitly listing the individual files at the root of the -# repository rather than just having `Files: *`. This is explicitly done to -# help downstream forks of the Rust compiler: this way, the files they add -# won't be automatically marked as authored by the Rust project. -Files: compiler/* - library/* - tests/* - src/* - .github/* - Cargo.lock - Cargo.toml - CODE_OF_CONDUCT.md - config.example.toml - configure - CONTRIBUTING.md - COPYRIGHT - INSTALL.md - LICENSE-APACHE - LICENSE-MIT - README.md - RELEASES.md - rustfmt.toml - rust-bors.toml - triagebot.toml - x - x.ps1 - x.py - .clang-format - .editorconfig - .git-blame-ignore-revs - .gitattributes - .gitignore - .gitmodules - .mailmap - .ignore -Copyright: The Rust Project Developers (see https://thanks.rust-lang.org) -License: MIT or Apache-2.0 - -Files: compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp -Copyright: 2003-2019 University of Illinois at Urbana-Champaign. - The Rust Project Developers (see https://thanks.rust-lang.org) -License: Apache-2.0 WITH LLVM-exception AND (Apache-2.0 OR MIT) - -Files: library/core/src/unicode/unicode_data.rs -Copyright: 1991-2022 Unicode, Inc. All rights reserved. -License: Unicode-DFS-2016 - -Files: library/std/src/sync/mpmc/* -Copyright: 2019 The Crossbeam Project Developers - The Rust Project Developers (see https://thanks.rust-lang.org) -License: MIT OR Apache-2.0 - -Files: library/std/src/sys/sync/mutex/fuchsia.rs -Copyright: 2016 The Fuchsia Authors - The Rust Project Developers (see https://thanks.rust-lang.org) -License: BSD-2-Clause AND (MIT OR Apache-2.0) - -Files: src/test/rustdoc/auxiliary/enum-primitive.rs -Copyright: 2015 Anders Kaseorg <andersk@mit.edu> -License: MIT - -Files: src/librustdoc/html/static/fonts/FiraSans* -Copyright: 2014, Mozilla Foundation - 2014, Telefonica S.A. -License: OFL-1.1 - -Files: src/librustdoc/html/static/fonts/NanumBarun* -Copyright: 2010 NAVER Corporation -License: OFL-1.1 - -Files: src/librustdoc/html/static/fonts/SourceCodePro* - src/librustdoc/html/static/fonts/SourceSerif4* -Copyright: 2010, 2012, 2014-2023, Adobe Systems Incorporated -License: OFL-1.1 - -Files: src/librustdoc/html/static/css/normalize.css -Copyright: Nicolas Gallagher and Jonathan Neal -License: MIT - -Files: src/librustdoc/html/static/css/rustdoc.css -Copyright: 2016 Ike Ku, Jessica Stokes and Leon Guan - The Rust Project Developers (see https://thanks.rust-lang.org) -License: MIT OR Apache-2.0 - -Files: src/doc/rustc-dev-guide/mermaid.min.js -Copyright: 2014-2021 Knut Sveidqvist -License: MIT - -Files: library/backtrace/* -Copyright: 2014 Alex Crichton - The Rust Project Developers (see https://thanks.rust-lang.org) -License: MIT OR Apache-2.0 - -Files: src/doc/embedded-book/* -Copyright: Rust on Embedded Devices Working Group - The Rust Project Developers (see https://thanks.rust-lang.org) -License: MIT OR Apache-2.0 OR CC-BY-SA-4.0 - -Files: src/doc/rust-by-example/* -Copyright: 2014 Jorge Aparicio - The Rust Project Developers (see https://thanks.rust-lang.org) -License: MIT OR Apache-2.0 - -# Reuse cannot process the LLVM source tree, and so the copyrights for the LLVM -# submodule are written out here manually. The collect-licence-metadata tool -# has a specific exception coded within it to ignore ./src/llvm-project so -# any time LLVM is updated, please revisit this section. The copyrights are -# taken from the relevant LLVM sub-folders: llvm, lld, lldb, compiler-rt and libunwind. -# -# The git hash for the CREDITS.TXT file is taken from the current git submodule -# commit for ./src/llvm-project. -# -# The copyright years were compiled by looking at all the relevant -# ./src/llvm-project/*/LICENSE.txt files - -Files: src/llvm-project/* -Copyright: 2003-2019 by the contributors listed in [CREDITS.TXT](https://github.com/rust-lang/llvm-project/blob/7738295178045041669876bf32b0543ec8319a5c/llvm/CREDITS.TXT) - 2010 Apple Inc - 2003-2019 University of Illinois at Urbana-Champaign. -License: NCSA AND Apache-2.0 WITH LLVM-exception diff --git a/Cargo.lock b/Cargo.lock index 1c1607e4c1a..64a7cec030a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,21 +285,6 @@ dependencies = [ ] [[package]] -name = "assert_cmd" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed72493ac66d5804837f480ab3766c72bdfab91a65e565fc54fa9e42db0073a8" -dependencies = [ - "anstyle", - "bstr", - "doc-comment", - "predicates", - "predicates-core", - "predicates-tree", - "wait-timeout", -] - -[[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1112,12 +1097,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] -name = "difflib" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" - -[[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1209,12 +1188,6 @@ dependencies = [ ] [[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] name = "either" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2204,21 +2177,6 @@ dependencies = [ ] [[package]] -name = "line-wrap" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd1bc4d24ad230d21fb898d1116b1801d7adfc449d42026475862ab48b11e70e" - -[[package]] -name = "linereader" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d921fea6860357575519aca014c6e22470585accdd543b370c404a8a72d0dd1d" -dependencies = [ - "memchr", -] - -[[package]] name = "linkchecker" version = "0.1.0" dependencies = [ @@ -2227,12 +2185,6 @@ dependencies = [ ] [[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] name = "lint-docs" version = "0.1.0" dependencies = [ @@ -2369,52 +2321,6 @@ dependencies = [ ] [[package]] -name = "mdbook-i18n-helpers" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c8f972ab672d366c3dad77ea5aa7bae68db2d25fbeb889849f97469d7b658e4" -dependencies = [ - "anyhow", - "chrono", - "mdbook", - "polib", - "pulldown-cmark 0.10.3", - "pulldown-cmark-to-cmark", - "regex", - "semver", - "serde_json", - "syntect", - "textwrap", -] - -[[package]] -name = "mdbook-trpl-listing" -version = "0.1.0" -dependencies = [ - "assert_cmd", - "clap", - "mdbook", - "pulldown-cmark 0.10.3", - "pulldown-cmark-to-cmark", - "serde_json", - "thiserror", - "toml 0.8.14", - "xmlparser", -] - -[[package]] -name = "mdbook-trpl-note" -version = "1.0.0" -dependencies = [ - "assert_cmd", - "clap", - "mdbook", - "pulldown-cmark 0.10.3", - "pulldown-cmark-to-cmark", - "serde_json", -] - -[[package]] name = "measureme" version = "11.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2599,12 +2505,76 @@ dependencies = [ ] [[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2692,28 +2662,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] -name = "onig" -version = "6.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" -dependencies = [ - "bitflags 1.3.2", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" -dependencies = [ - "cc", - "pkg-config", -] - -[[package]] name = "opener" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3013,29 +2961,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] -name = "plist" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d34169e64b3c7a80c8621a48adaf44e0cf62c78a9b25dd9dd35f1881a17cf9" -dependencies = [ - "base64", - "indexmap", - "line-wrap", - "quick-xml", - "serde", - "time", -] - -[[package]] -name = "polib" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b393b155cf9be86249cba1b56cc81be0e6212c66d94ac0d76d37a1761f3bb1b" -dependencies = [ - "linereader", -] - -[[package]] name = "polonius-engine" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3071,33 +2996,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] -name = "predicates" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" -dependencies = [ - "anstyle", - "difflib", - "predicates-core", -] - -[[package]] -name = "predicates-core" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" - -[[package]] -name = "predicates-tree" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" -dependencies = [ - "predicates-core", - "termtree", -] - -[[package]] name = "prettydiff" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3166,7 +3064,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" dependencies = [ "bitflags 2.5.0", - "getopts", "memchr", "pulldown-cmark-escape 0.10.1", "unicase", @@ -3197,30 +3094,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" [[package]] -name = "pulldown-cmark-to-cmark" -version = "13.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f609795c8d835f79dcfcf768415b9fb57ef1b74891e99f86e73f43a7a257163b" -dependencies = [ - "pulldown-cmark 0.10.3", -] - -[[package]] name = "punycode" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9e1dcb320d6839f6edb64f7a4a59d39b30480d4d1765b56873f7c858538a5fe" [[package]] -name = "quick-xml" -version = "0.31.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" -dependencies = [ - "memchr", -] - -[[package]] name = "quine-mc_cluskey" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -3455,18 +3334,6 @@ dependencies = [ ] [[package]] -name = "rustbook" -version = "0.1.0" -dependencies = [ - "clap", - "env_logger", - "mdbook", - "mdbook-i18n-helpers", - "mdbook-trpl-listing", - "mdbook-trpl-note", -] - -[[package]] name = "rustc-build-sysroot" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5486,28 +5353,6 @@ dependencies = [ ] [[package]] -name = "syntect" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" -dependencies = [ - "bincode", - "bitflags 1.3.2", - "flate2", - "fnv", - "once_cell", - "onig", - "plist", - "regex-syntax 0.8.4", - "serde", - "serde_derive", - "serde_json", - "thiserror", - "walkdir", - "yaml-rust", -] - -[[package]] name = "sysinfo" version = "0.30.12" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -5615,12 +5460,6 @@ dependencies = [ ] [[package]] -name = "termtree" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" - -[[package]] name = "test" version = "0.0.0" dependencies = [ @@ -5631,10 +5470,15 @@ dependencies = [ ] [[package]] -name = "textwrap" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +name = "test-float-parse" +version = "0.1.0" +dependencies = [ + "indicatif", + "num", + "rand", + "rand_chacha", + "rayon", +] [[package]] name = "thin-vec" @@ -5799,19 +5643,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.19.15", -] - -[[package]] -name = "toml" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.22.14", + "toml_edit", ] [[package]] @@ -5833,20 +5665,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.6.13", + "winnow", ] [[package]] @@ -6257,15 +6076,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] -name = "wait-timeout" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" -dependencies = [ - "libc", -] - -[[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6670,15 +6480,6 @@ dependencies = [ ] [[package]] -name = "winnow" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" -dependencies = [ - "memchr", -] - -[[package]] name = "wit-component" version = "0.210.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6733,12 +6534,6 @@ dependencies = [ ] [[package]] -name = "xmlparser" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" - -[[package]] name = "xz2" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -6748,15 +6543,6 @@ dependencies = [ ] [[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - -[[package]] name = "yansi-term" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml index ce87a8c20b7..178a5ab9408 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "compiler/rustc", "library/std", "library/sysroot", + "src/etc/test-float-parse", "src/rustdoc-json-types", "src/tools/build_helper", "src/tools/cargotest", @@ -15,7 +16,6 @@ members = [ "src/tools/linkchecker", "src/tools/lint-docs", "src/tools/miropt-test-tools", - "src/tools/rustbook", "src/tools/unstable-book-gen", "src/tools/tidy", "src/tools/tier-check", @@ -109,6 +109,18 @@ strip = true debug = 0 strip = true +# Bigint libraries are slow without optimization, speed up testing +[profile.dev.package.test-float-parse] +opt-level = 3 + +# Speed up the binary as much as possible +[profile.release.package.test-float-parse] +opt-level = 3 +codegen-units = 1 +# FIXME: LTO cannot be enabled for binaries in a workspace +# <https://github.com/rust-lang/cargo/issues/9330> +# lto = true + [patch.crates-io] # See comments in `library/rustc-std-workspace-core/README.md` for what's going on # here diff --git a/LICENSES/CC-BY-3.0.txt b/LICENSES/CC-BY-3.0.txt deleted file mode 100644 index bd32fa8477b..00000000000 --- a/LICENSES/CC-BY-3.0.txt +++ /dev/null @@ -1,319 +0,0 @@ -Creative Commons Legal Code - -Attribution 3.0 Unported - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR - DAMAGES RESULTING FROM ITS USE. - -License - -THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE -COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY -COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS -AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. - -BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE -TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY -BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS -CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND -CONDITIONS. - -1. Definitions - - a. "Adaptation" means a work based upon the Work, or upon the Work and - other pre-existing works, such as a translation, adaptation, - derivative work, arrangement of music or other alterations of a - literary or artistic work, or phonogram or performance and includes - cinematographic adaptations or any other form in which the Work may be - recast, transformed, or adapted including in any form recognizably - derived from the original, except that a work that constitutes a - Collection will not be considered an Adaptation for the purpose of - this License. For the avoidance of doubt, where the Work is a musical - work, performance or phonogram, the synchronization of the Work in - timed-relation with a moving image ("synching") will be considered an - Adaptation for the purpose of this License. - b. "Collection" means a collection of literary or artistic works, such as - encyclopedias and anthologies, or performances, phonograms or - broadcasts, or other works or subject matter other than works listed - in Section 1(f) below, which, by reason of the selection and - arrangement of their contents, constitute intellectual creations, in - which the Work is included in its entirety in unmodified form along - with one or more other contributions, each constituting separate and - independent works in themselves, which together are assembled into a - collective whole. A work that constitutes a Collection will not be - considered an Adaptation (as defined above) for the purposes of this - License. - c. "Distribute" means to make available to the public the original and - copies of the Work or Adaptation, as appropriate, through sale or - other transfer of ownership. - d. "Licensor" means the individual, individuals, entity or entities that - offer(s) the Work under the terms of this License. - e. "Original Author" means, in the case of a literary or artistic work, - the individual, individuals, entity or entities who created the Work - or if no individual or entity can be identified, the publisher; and in - addition (i) in the case of a performance the actors, singers, - musicians, dancers, and other persons who act, sing, deliver, declaim, - play in, interpret or otherwise perform literary or artistic works or - expressions of folklore; (ii) in the case of a phonogram the producer - being the person or legal entity who first fixes the sounds of a - performance or other sounds; and, (iii) in the case of broadcasts, the - organization that transmits the broadcast. - f. "Work" means the literary and/or artistic work offered under the terms - of this License including without limitation any production in the - literary, scientific and artistic domain, whatever may be the mode or - form of its expression including digital form, such as a book, - pamphlet and other writing; a lecture, address, sermon or other work - of the same nature; a dramatic or dramatico-musical work; a - choreographic work or entertainment in dumb show; a musical - composition with or without words; a cinematographic work to which are - assimilated works expressed by a process analogous to cinematography; - a work of drawing, painting, architecture, sculpture, engraving or - lithography; a photographic work to which are assimilated works - expressed by a process analogous to photography; a work of applied - art; an illustration, map, plan, sketch or three-dimensional work - relative to geography, topography, architecture or science; a - performance; a broadcast; a phonogram; a compilation of data to the - extent it is protected as a copyrightable work; or a work performed by - a variety or circus performer to the extent it is not otherwise - considered a literary or artistic work. - g. "You" means an individual or entity exercising rights under this - License who has not previously violated the terms of this License with - respect to the Work, or who has received express permission from the - Licensor to exercise rights under this License despite a previous - violation. - h. "Publicly Perform" means to perform public recitations of the Work and - to communicate to the public those public recitations, by any means or - process, including by wire or wireless means or public digital - performances; to make available to the public Works in such a way that - members of the public may access these Works from a place and at a - place individually chosen by them; to perform the Work to the public - by any means or process and the communication to the public of the - performances of the Work, including by public digital performance; to - broadcast and rebroadcast the Work by any means including signs, - sounds or images. - i. "Reproduce" means to make copies of the Work by any means including - without limitation by sound or visual recordings and the right of - fixation and reproducing fixations of the Work, including storage of a - protected performance or phonogram in digital form or other electronic - medium. - -2. Fair Dealing Rights. Nothing in this License is intended to reduce, -limit, or restrict any uses free from copyright or rights arising from -limitations or exceptions that are provided for in connection with the -copyright protection under copyright law or other applicable laws. - -3. License Grant. Subject to the terms and conditions of this License, -Licensor hereby grants You a worldwide, royalty-free, non-exclusive, -perpetual (for the duration of the applicable copyright) license to -exercise the rights in the Work as stated below: - - a. to Reproduce the Work, to incorporate the Work into one or more - Collections, and to Reproduce the Work as incorporated in the - Collections; - b. to create and Reproduce Adaptations provided that any such Adaptation, - including any translation in any medium, takes reasonable steps to - clearly label, demarcate or otherwise identify that changes were made - to the original Work. For example, a translation could be marked "The - original work was translated from English to Spanish," or a - modification could indicate "The original work has been modified."; - c. to Distribute and Publicly Perform the Work including as incorporated - in Collections; and, - d. to Distribute and Publicly Perform Adaptations. - e. For the avoidance of doubt: - - i. Non-waivable Compulsory License Schemes. In those jurisdictions in - which the right to collect royalties through any statutory or - compulsory licensing scheme cannot be waived, the Licensor - reserves the exclusive right to collect such royalties for any - exercise by You of the rights granted under this License; - ii. Waivable Compulsory License Schemes. In those jurisdictions in - which the right to collect royalties through any statutory or - compulsory licensing scheme can be waived, the Licensor waives the - exclusive right to collect such royalties for any exercise by You - of the rights granted under this License; and, - iii. Voluntary License Schemes. The Licensor waives the right to - collect royalties, whether individually or, in the event that the - Licensor is a member of a collecting society that administers - voluntary licensing schemes, via that society, from any exercise - by You of the rights granted under this License. - -The above rights may be exercised in all media and formats whether now -known or hereafter devised. The above rights include the right to make -such modifications as are technically necessary to exercise the rights in -other media and formats. Subject to Section 8(f), all rights not expressly -granted by Licensor are hereby reserved. - -4. Restrictions. The license granted in Section 3 above is expressly made -subject to and limited by the following restrictions: - - a. You may Distribute or Publicly Perform the Work only under the terms - of this License. You must include a copy of, or the Uniform Resource - Identifier (URI) for, this License with every copy of the Work You - Distribute or Publicly Perform. You may not offer or impose any terms - on the Work that restrict the terms of this License or the ability of - the recipient of the Work to exercise the rights granted to that - recipient under the terms of the License. You may not sublicense the - Work. You must keep intact all notices that refer to this License and - to the disclaimer of warranties with every copy of the Work You - Distribute or Publicly Perform. When You Distribute or Publicly - Perform the Work, You may not impose any effective technological - measures on the Work that restrict the ability of a recipient of the - Work from You to exercise the rights granted to that recipient under - the terms of the License. This Section 4(a) applies to the Work as - incorporated in a Collection, but this does not require the Collection - apart from the Work itself to be made subject to the terms of this - License. If You create a Collection, upon notice from any Licensor You - must, to the extent practicable, remove from the Collection any credit - as required by Section 4(b), as requested. If You create an - Adaptation, upon notice from any Licensor You must, to the extent - practicable, remove from the Adaptation any credit as required by - Section 4(b), as requested. - b. If You Distribute, or Publicly Perform the Work or any Adaptations or - Collections, You must, unless a request has been made pursuant to - Section 4(a), keep intact all copyright notices for the Work and - provide, reasonable to the medium or means You are utilizing: (i) the - name of the Original Author (or pseudonym, if applicable) if supplied, - and/or if the Original Author and/or Licensor designate another party - or parties (e.g., a sponsor institute, publishing entity, journal) for - attribution ("Attribution Parties") in Licensor's copyright notice, - terms of service or by other reasonable means, the name of such party - or parties; (ii) the title of the Work if supplied; (iii) to the - extent reasonably practicable, the URI, if any, that Licensor - specifies to be associated with the Work, unless such URI does not - refer to the copyright notice or licensing information for the Work; - and (iv) , consistent with Section 3(b), in the case of an Adaptation, - a credit identifying the use of the Work in the Adaptation (e.g., - "French translation of the Work by Original Author," or "Screenplay - based on original Work by Original Author"). The credit required by - this Section 4 (b) may be implemented in any reasonable manner; - provided, however, that in the case of a Adaptation or Collection, at - a minimum such credit will appear, if a credit for all contributing - authors of the Adaptation or Collection appears, then as part of these - credits and in a manner at least as prominent as the credits for the - other contributing authors. For the avoidance of doubt, You may only - use the credit required by this Section for the purpose of attribution - in the manner set out above and, by exercising Your rights under this - License, You may not implicitly or explicitly assert or imply any - connection with, sponsorship or endorsement by the Original Author, - Licensor and/or Attribution Parties, as appropriate, of You or Your - use of the Work, without the separate, express prior written - permission of the Original Author, Licensor and/or Attribution - Parties. - c. Except as otherwise agreed in writing by the Licensor or as may be - otherwise permitted by applicable law, if You Reproduce, Distribute or - Publicly Perform the Work either by itself or as part of any - Adaptations or Collections, You must not distort, mutilate, modify or - take other derogatory action in relation to the Work which would be - prejudicial to the Original Author's honor or reputation. Licensor - agrees that in those jurisdictions (e.g. Japan), in which any exercise - of the right granted in Section 3(b) of this License (the right to - make Adaptations) would be deemed to be a distortion, mutilation, - modification or other derogatory action prejudicial to the Original - Author's honor and reputation, the Licensor will waive or not assert, - as appropriate, this Section, to the fullest extent permitted by the - applicable national law, to enable You to reasonably exercise Your - right under Section 3(b) of this License (right to make Adaptations) - but not otherwise. - -5. Representations, Warranties and Disclaimer - -UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR -OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY -KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, -INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, -FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF -LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, -WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION -OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. - -6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE -LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR -ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES -ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS -BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - -7. Termination - - a. This License and the rights granted hereunder will terminate - automatically upon any breach by You of the terms of this License. - Individuals or entities who have received Adaptations or Collections - from You under this License, however, will not have their licenses - terminated provided such individuals or entities remain in full - compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will - survive any termination of this License. - b. Subject to the above terms and conditions, the license granted here is - perpetual (for the duration of the applicable copyright in the Work). - Notwithstanding the above, Licensor reserves the right to release the - Work under different license terms or to stop distributing the Work at - any time; provided, however that any such election will not serve to - withdraw this License (or any other license that has been, or is - required to be, granted under the terms of this License), and this - License will continue in full force and effect unless terminated as - stated above. - -8. Miscellaneous - - a. Each time You Distribute or Publicly Perform the Work or a Collection, - the Licensor offers to the recipient a license to the Work on the same - terms and conditions as the license granted to You under this License. - b. Each time You Distribute or Publicly Perform an Adaptation, Licensor - offers to the recipient a license to the original Work on the same - terms and conditions as the license granted to You under this License. - c. If any provision of this License is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability of - the remainder of the terms of this License, and without further action - by the parties to this agreement, such provision shall be reformed to - the minimum extent necessary to make such provision valid and - enforceable. - d. No term or provision of this License shall be deemed waived and no - breach consented to unless such waiver or consent shall be in writing - and signed by the party to be charged with such waiver or consent. - e. This License constitutes the entire agreement between the parties with - respect to the Work licensed here. There are no understandings, - agreements or representations with respect to the Work not specified - here. Licensor shall not be bound by any additional provisions that - may appear in any communication from You. This License may not be - modified without the mutual written agreement of the Licensor and You. - f. The rights granted under, and the subject matter referenced, in this - License were drafted utilizing the terminology of the Berne Convention - for the Protection of Literary and Artistic Works (as amended on - September 28, 1979), the Rome Convention of 1961, the WIPO Copyright - Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 - and the Universal Copyright Convention (as revised on July 24, 1971). - These rights and subject matter take effect in the relevant - jurisdiction in which the License terms are sought to be enforced - according to the corresponding provisions of the implementation of - those treaty provisions in the applicable national law. If the - standard suite of rights granted under applicable copyright law - includes additional rights not granted under this License, such - additional rights are deemed to be included in the License; this - License is not intended to restrict the license of any rights under - applicable law. - - -Creative Commons Notice - - Creative Commons is not a party to this License, and makes no warranty - whatsoever in connection with the Work. Creative Commons will not be - liable to You or any party on any legal theory for any damages - whatsoever, including without limitation any general, special, - incidental or consequential damages arising in connection to this - license. Notwithstanding the foregoing two (2) sentences, if Creative - Commons has expressly identified itself as the Licensor hereunder, it - shall have all rights and obligations of Licensor. - - Except for the limited purpose of indicating to the public that the - Work is licensed under the CCPL, Creative Commons does not authorize - the use by either party of the trademark "Creative Commons" or any - related trademark or logo of Creative Commons without the prior - written consent of Creative Commons. Any permitted use will be in - compliance with Creative Commons' then-current trademark usage - guidelines, as may be published on its website or otherwise made - available upon request from time to time. For the avoidance of doubt, - this trademark restriction does not form part of this License. - - Creative Commons may be contacted at https://creativecommons.org/. \ No newline at end of file diff --git a/LICENSES/CC0-1.0.txt b/LICENSES/CC0-1.0.txt deleted file mode 100644 index 0e259d42c99..00000000000 --- a/LICENSES/CC0-1.0.txt +++ /dev/null @@ -1,121 +0,0 @@ -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. diff --git a/REUSE.toml b/REUSE.toml new file mode 100644 index 00000000000..1a30d8016c9 --- /dev/null +++ b/REUSE.toml @@ -0,0 +1,170 @@ +version = 1 + +# Reuse annotations file. +# +# This file controls how reuse-tool finds copyright and license notices within +# source files. As the tool has a habit of picking up random uses of the word +# 'Copyright' within source code, and because it will complain that other files +# do not contain any specific copyright and license notifications, we usually +# just set a blanket license and copyright notice for a whole sub-tree at a +# time. +# +# See https://reuse.software and https://github.com/fsfe/reuse-tool for more +# details. We currently use reuse-tool version 4.0.3. + +[[annotations]] +path = [ + "compiler/**", + "library/**", + "tests/**", + "src/**", + ".github/**", + "Cargo.lock", + "Cargo.toml", + "CODE_OF_CONDUCT.md", + "config.example.toml", + "configure", + "CONTRIBUTING.md", + "COPYRIGHT", + "INSTALL.md", + "LICENSE-APACHE", + "LICENSE-MIT", + "README.md", + "RELEASES.md", + "REUSE.toml", + "rustfmt.toml", + "rust-bors.toml", + "triagebot.toml", + "x", + "x.ps1", + "x.py", + ".clang-format", + ".editorconfig", + ".git-blame-ignore-revs", + ".gitattributes", + ".gitignore", + ".gitmodules", + ".mailmap", + ".ignore", +] +precedence = "override" +SPDX-FileCopyrightText = "The Rust Project Developers (see https://thanks.rust-lang.org)" +SPDX-License-Identifier = "MIT or Apache-2.0" + +[[annotations]] +path = "compiler/rustc_llvm/llvm-wrapper/SymbolWrapper.cpp" +precedence = "override" +SPDX-FileCopyrightText = [ + "2003-2019 University of Illinois at Urbana-Champaign.", + "The Rust Project Developers (see https://thanks.rust-lang.org)", +] +SPDX-License-Identifier = "Apache-2.0 WITH LLVM-exception AND (Apache-2.0 OR MIT)" + +[[annotations]] +path = "library/core/src/unicode/unicode_data.rs" +precedence = "override" +SPDX-FileCopyrightText = "1991-2022 Unicode, Inc. All rights reserved." +SPDX-License-Identifier = "Unicode-DFS-2016" + +[[annotations]] +path = "library/std/src/sync/mpmc/**" +precedence = "override" +SPDX-FileCopyrightText = [ + "2019 The Crossbeam Project Developers", + "The Rust Project Developers (see https://thanks.rust-lang.org)", +] +SPDX-License-Identifier = "MIT OR Apache-2.0" + +[[annotations]] +path = "library/std/src/sys/sync/mutex/fuchsia.rs" +precedence = "override" +SPDX-FileCopyrightText = [ + "2016 The Fuchsia Authors", + "The Rust Project Developers (see https://thanks.rust-lang.org)", +] +SPDX-License-Identifier = "BSD-2-Clause AND (MIT OR Apache-2.0)" + +[[annotations]] +path = "src/test/rustdoc/auxiliary/enum-primitive.rs" +precedence = "override" +SPDX-FileCopyrightText = "2015 Anders Kaseorg <andersk@mit.edu>" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "src/librustdoc/html/static/fonts/FiraSans**" +precedence = "override" +SPDX-FileCopyrightText = ["2014, Mozilla Foundation", "2014, Telefonica S.A."] +SPDX-License-Identifier = "OFL-1.1" + +[[annotations]] +path = "src/librustdoc/html/static/fonts/NanumBarun**" +precedence = "override" +SPDX-FileCopyrightText = "2010 NAVER Corporation" +SPDX-License-Identifier = "OFL-1.1" + +[[annotations]] +path = [ + "src/librustdoc/html/static/fonts/SourceCodePro**", + "src/librustdoc/html/static/fonts/SourceSerif4**", +] +precedence = "override" +SPDX-FileCopyrightText = "2010, 2012, 2014-2023, Adobe Systems Incorporated" +SPDX-License-Identifier = "OFL-1.1" + +[[annotations]] +path = "src/librustdoc/html/static/css/normalize.css" +precedence = "override" +SPDX-FileCopyrightText = "Nicolas Gallagher and Jonathan Neal" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "src/librustdoc/html/static/css/rustdoc.css" +precedence = "override" +SPDX-FileCopyrightText = [ + "2016 Ike Ku, Jessica Stokes and Leon Guan", + "The Rust Project Developers (see https://thanks.rust-lang.org)", +] +SPDX-License-Identifier = "MIT OR Apache-2.0" + +[[annotations]] +path = "src/doc/rustc-dev-guide/mermaid.min.js" +precedence = "override" +SPDX-FileCopyrightText = "2014-2021 Knut Sveidqvist" +SPDX-License-Identifier = "MIT" + +[[annotations]] +path = "library/backtrace/**" +precedence = "override" +SPDX-FileCopyrightText = [ + "2014 Alex Crichton", + "The Rust Project Developers (see https://thanks.rust-lang.org)", +] +SPDX-License-Identifier = "MIT OR Apache-2.0" + +[[annotations]] +path = "src/doc/embedded-book/**" +precedence = "override" +SPDX-FileCopyrightText = [ + "Rust on Embedded Devices Working Group", + "The Rust Project Developers (see https://thanks.rust-lang.org)", +] +SPDX-License-Identifier = "MIT OR Apache-2.0 OR CC-BY-SA-4.0" + +[[annotations]] +path = "src/doc/rust-by-example/**" +precedence = "override" +SPDX-FileCopyrightText = [ + "2014 Jorge Aparicio", + "The Rust Project Developers (see https://thanks.rust-lang.org)", +] +SPDX-License-Identifier = "MIT OR Apache-2.0" + +[[annotations]] +path = "src/llvm-project/**" +precedence = "override" +SPDX-FileCopyrightText = [ + "2003-2019 by the contributors listed in [CREDITS.TXT](https://github.com/rust-lang/llvm-project/blob/7738295178045041669876bf32b0543ec8319a5c/llvm/CREDITS.TXT)", + "2010 Apple Inc", + "2003-2019 University of Illinois at Urbana-Champaign.", +] +SPDX-License-Identifier = "NCSA AND Apache-2.0 WITH LLVM-exception" diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl index 8f7dd774207..ca0b7f2ac3a 100644 --- a/compiler/rustc_ast_passes/messages.ftl +++ b/compiler/rustc_ast_passes/messages.ftl @@ -120,6 +120,9 @@ ast_passes_fn_without_body = ast_passes_forbidden_bound = bounds cannot be used in this context +ast_passes_forbidden_const_param = + late-bound const parameters cannot be used currently + ast_passes_forbidden_default = `default` is only allowed on items in trait impls .label = `default` because of this diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 783bca6b695..215ccd2ab4d 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -70,6 +70,13 @@ pub struct ForbiddenBound { } #[derive(Diagnostic)] +#[diag(ast_passes_forbidden_const_param)] +pub struct ForbiddenConstParam { + #[primary_span] + pub const_param_spans: Vec<Span>, +} + +#[derive(Diagnostic)] #[diag(ast_passes_fn_param_too_many)] pub struct FnParamTooMany { #[primary_span] diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 2178b65727d..e91dfb27766 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -162,6 +162,22 @@ impl<'a> PostExpansionVisitor<'a> { crate::fluent_generated::ast_passes_forbidden_non_lifetime_param ); + // FIXME(non_lifetime_binders): Const bound params are pretty broken. + // Let's keep users from using this feature accidentally. + if self.features.non_lifetime_binders { + let const_param_spans: Vec<_> = params + .iter() + .filter_map(|param| match param.kind { + ast::GenericParamKind::Const { .. } => Some(param.ident.span), + _ => None, + }) + .collect(); + + if !const_param_spans.is_empty() { + self.sess.dcx().emit_err(errors::ForbiddenConstParam { const_param_spans }); + } + } + for param in params { if !param.bounds.is_empty() { let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect(); diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 4cd0d9cb294..cbee01f2e2d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -1,6 +1,5 @@ use rustc_errors::Diag; use rustc_hir::def_id::LocalDefId; -use rustc_infer::error_reporting::infer::nice_region_error::NiceRegionError; use rustc_infer::infer::canonical::Canonical; use rustc_infer::infer::region_constraints::Constraint; use rustc_infer::infer::region_constraints::RegionConstraintData; @@ -14,6 +13,8 @@ use rustc_middle::ty::RegionVid; use rustc_middle::ty::UniverseIndex; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc_span::Span; +use rustc_trait_selection::error_reporting::infer::nice_region_error::NiceRegionError; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::query::type_op; use rustc_trait_selection::traits::ObligationCtxt; use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index a4fd00efe05..b147567001d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -35,8 +35,8 @@ use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{BytePos, Span, Symbol}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; use rustc_trait_selection::error_reporting::traits::FindExprBySpan; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{Obligation, ObligationCause, ObligationCtxt}; use std::iter; diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index f97459d16ba..d505d9c004e 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -27,7 +27,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::source_map::Spanned; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_target::abi::{FieldIdx, VariantIdx}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ type_known_to_meet_bound_modulo_regions, FulfillmentErrorCode, diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 26b0d23b166..a7bf6d636c1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -16,7 +16,7 @@ use rustc_middle::{ use rustc_span::symbol::{kw, Symbol}; use rustc_span::{sym, BytePos, DesugaringKind, Span}; use rustc_target::abi::FieldIdx; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 6cf797b4761..6b7bd7dc0d8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -10,11 +10,6 @@ use rustc_hir::GenericBound::Trait; use rustc_hir::QPath::Resolved; use rustc_hir::WherePredicate::BoundPredicate; use rustc_hir::{PolyTraitRef, TyKind, WhereBoundPredicate}; -use rustc_infer::error_reporting::infer::nice_region_error::{ - self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, - HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, -}; -use rustc_infer::error_reporting::infer::region::unexpected_hidden_region_diagnostic; use rustc_infer::infer::{NllRegionVariableOrigin, RelateParamBound}; use rustc_middle::bug; use rustc_middle::hir::place::PlaceBase; @@ -25,6 +20,12 @@ use rustc_middle::ty::{self, RegionVid, Ty}; use rustc_middle::ty::{Region, TyCtxt}; use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; +use rustc_trait_selection::error_reporting::infer::nice_region_error::{ + self, find_anon_type, find_param_with_region, suggest_adding_lifetime_params, + HirTraitObjectVisitor, NiceRegionError, TraitObjectVisitor, +}; +use rustc_trait_selection::error_reporting::infer::region::unexpected_hidden_region_diagnostic; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{Obligation, ObligationCtxt}; diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 356416d1a75..6443c5e92e8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::{GenericArgKind, GenericArgsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use crate::{universal_regions::DefiningTy, MirBorrowckCtxt}; @@ -457,8 +458,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { ) -> RegionNameHighlight { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(self.infcx.tcx, needle_fr, counter); - let type_name = - self.infcx.extract_inference_diagnostics_data(ty.into(), Some(highlight)).name; + let type_name = self + .infcx + .err_ctxt() + .extract_inference_diagnostics_data(ty.into(), Some(highlight)) + .name; debug!( "highlight_if_we_cannot_match_hir_ty: type_name={:?} needle_fr={:?}", @@ -872,8 +876,11 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(tcx, fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = - self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; + let type_name = self + .infcx + .err_ctxt() + .extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)) + .name; let yield_span = match tcx.hir_node(self.mir_hir_id()) { hir::Node::Expr(hir::Expr { diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index c0e91ce32e3..cf28ba224d6 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{GenericArgKind, GenericArgs}; use rustc_span::Span; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::ObligationCtxt; use crate::session_diagnostics::LifetimeMismatchOpaqueParam; diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index 431a704687d..e4c2e0fced7 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -11,7 +11,7 @@ use rustc_middle::traits::query::OutlivesBound; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::{self, RegionVid, Ty, TypeVisitableExt}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::solve::deeply_normalize; use rustc_trait_selection::traits::query::type_op::{self, TypeOp}; use std::rc::Rc; diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 97e2344ff30..f6b54335829 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -38,7 +38,44 @@ pub(crate) fn expand_deriving_const_param_ty( ) { let trait_def = TraitDef { span, - path: path_std!(marker::ConstParamTy), + path: path_std!(marker::ConstParamTy_), + skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, + additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))], + supports_unions: false, + methods: Vec::new(), + associated_types: Vec::new(), + is_const, + }; + + trait_def.expand(cx, mitem, item, push); + + let trait_def = TraitDef { + span, + path: path_std!(marker::UnsizedConstParamTy), + skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, + additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))], + supports_unions: false, + methods: Vec::new(), + associated_types: Vec::new(), + is_const, + }; + + trait_def.expand(cx, mitem, item, push); +} + +pub(crate) fn expand_deriving_unsized_const_param_ty( + cx: &ExtCtxt<'_>, + span: Span, + mitem: &MetaItem, + item: &Annotatable, + push: &mut dyn FnMut(Annotatable), + is_const: bool, +) { + let trait_def = TraitDef { + span, + path: path_std!(marker::UnsizedConstParamTy), skip_path_as_bound: false, needs_copy_as_bound_if_packed: false, additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))], diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index f8d93666145..c77ff9eb13c 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -118,6 +118,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { Clone: clone::expand_deriving_clone, Copy: bounds::expand_deriving_copy, ConstParamTy: bounds::expand_deriving_const_param_ty, + UnsizedConstParamTy: bounds::expand_deriving_unsized_const_param_ty, Debug: debug::expand_deriving_debug, Default: default::expand_deriving_default, Eq: eq::expand_deriving_eq, diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md index eb21e027dd0..3b3c86a1bd1 100644 --- a/compiler/rustc_codegen_cranelift/Readme.md +++ b/compiler/rustc_codegen_cranelift/Readme.md @@ -70,7 +70,7 @@ For more docs on how to build and test see [build_system/usage.txt](build_system |FreeBSD|✅[^no-rustup]|❓|❓|❓| |AIX|❌[^xcoff]|N/A|N/A|❌[^xcoff]| |Other unixes|❓|❓|❓|❓| -|macOS|✅|✅[^no-rustup]|N/A|N/A| +|macOS|✅|✅|N/A|N/A| |Windows|✅[^no-rustup]|❌|N/A|N/A| ✅: Fully supported and tested diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index ac5aaea561c..24cf3f061a5 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -10,12 +10,12 @@ use std::mem; use cranelift_codegen::ir::{ArgumentPurpose, SigRef}; use cranelift_codegen::isa::CallConv; use cranelift_module::ModuleError; +use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_codegen_ssa::errors::CompilerBuiltinsCannotCall; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::TypeVisitableExt; -use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_session::Session; use rustc_span::source_map::Spanned; use rustc_target::abi::call::{Conv, FnAbi, PassMode}; diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 5adbbb09ac8..9bc7b57c537 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -5,13 +5,13 @@ use cranelift_codegen::CodegenError; use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext}; use cranelift_module::ModuleError; use rustc_ast::InlineAsmOptions; +use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::TypeVisitableExt; -use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use crate::constant::ConstantCx; use crate::debuginfo::{FunctionDebugContext, TypeDebugContext}; diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 192e6c91ea3..8d3d5ac98e1 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -24,7 +24,6 @@ extern crate rustc_hir; extern crate rustc_incremental; extern crate rustc_index; extern crate rustc_metadata; -extern crate rustc_monomorphize; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index e7669470026..3877460fcdb 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -271,6 +271,17 @@ fn stackprotector_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { Some(sspattr.create_attr(cx.llcx)) } +fn backchain_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { + if cx.sess().target.arch != "s390x" { + return None; + } + + let requested_features = cx.sess().opts.cg.target_feature.split(','); + let found_positive = requested_features.clone().any(|r| r == "+backchain"); + + if found_positive { Some(llvm::CreateAttrString(cx.llcx, "backchain")) } else { None } +} + pub fn target_cpu_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> &'ll Attribute { let target_cpu = llvm_util::target_cpu(cx.tcx.sess); llvm::CreateAttrStringValue(cx.llcx, "target-cpu", target_cpu) @@ -447,6 +458,9 @@ pub fn from_fn_attrs<'ll, 'tcx>( if let Some(align) = codegen_fn_attrs.alignment { llvm::set_alignment(llfn, align); } + if let Some(backchain) = backchain_attr(cx) { + to_add.push(backchain); + } to_add.extend(sanitize_attrs(cx, codegen_fn_attrs.no_sanitize)); to_add.extend(patchable_function_entry_attrs(cx, codegen_fn_attrs.patchable_function_entry)); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 98dc8ac86d2..4d56d1d3b1a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -14,7 +14,7 @@ use rustc_session::config::{PrintKind, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; use rustc_target::spec::{MergeFunctions, PanicStrategy}; -use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; +use rustc_target::target_features::{RUSTC_SPECIAL_FEATURES, RUSTC_SPECIFIC_FEATURES}; use std::ffi::{c_char, c_void, CStr, CString}; use std::fmt::Write; @@ -321,6 +321,10 @@ pub fn target_features(sess: &Session, allow_unstable: bool) -> Vec<Symbol> { } }) .filter(|feature| { + // skip checking special features, as LLVM may not understands them + if RUSTC_SPECIAL_FEATURES.contains(feature) { + return true; + } // check that all features in a given smallvec are enabled for llvm_feature in to_llvm_features(sess, feature) { let cstr = SmallCStr::new(llvm_feature); @@ -546,6 +550,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str // -Ctarget-features let supported_features = sess.target.supported_target_features(); + let (llvm_major, _, _) = get_version(); let mut featsmap = FxHashMap::default(); let feats = sess .opts @@ -604,6 +609,13 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str if RUSTC_SPECIFIC_FEATURES.contains(&feature) { return None; } + + // if the target-feature is "backchain" and LLVM version is greater than 18 + // then we also need to add "+backchain" to the target-features attribute. + // otherwise, we will only add the naked `backchain` attribute to the attribute-group. + if feature == "backchain" && llvm_major < 18 { + return None; + } // ... otherwise though we run through `to_llvm_features` when // passing requests down to LLVM. This means that all in-language // features also work on the command line instead of having two diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 137f14fe706..399ac485850 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -806,6 +806,34 @@ pub fn codegen_crate<B: ExtraBackendMethods>( ongoing_codegen } +/// Returns whether a call from the current crate to the [`Instance`] would produce a call +/// from `compiler_builtins` to a symbol the linker must resolve. +/// +/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some +/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is +/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any +/// unlinkable calls. +/// +/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker. +pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>( + tcx: TyCtxt<'tcx>, + instance: Instance<'tcx>, +) -> bool { + fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name { + name.as_str().starts_with("llvm.") + } else { + false + } + } + + let def_id = instance.def_id(); + !def_id.is_local() + && tcx.is_compiler_builtins(LOCAL_CRATE) + && !is_llvm_intrinsic(tcx, def_id) + && !tcx.should_codegen_locally(instance) +} + impl CrateInfo { pub fn new(tcx: TyCtxt<'_>, target_cpu: String) -> CrateInfo { let crate_types = tcx.crate_types().to_vec(); diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 6a5525dc2b3..c9c8f02c491 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -3,7 +3,7 @@ use super::operand::OperandValue::{Immediate, Pair, Ref, ZeroSized}; use super::place::{PlaceRef, PlaceValue}; use super::{CachedLlbb, FunctionCx, LocalRef}; -use crate::base; +use crate::base::{self, is_call_from_compiler_builtins_to_upstream_monomorphization}; use crate::common::{self, IntPredicate}; use crate::errors::CompilerBuiltinsCannotCall; use crate::meth; @@ -18,7 +18,6 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::{self, Instance, Ty}; use rustc_middle::{bug, span_bug}; -use rustc_monomorphize::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_session::config::OptLevel; use rustc_span::{source_map::Spanned, sym, Span}; use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg}; diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index cea164df617..e7cee5220d6 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -82,6 +82,7 @@ pub fn from_target_feature( Some(sym::prfchw_target_feature) => rust_features.prfchw_target_feature, Some(sym::x86_amx_intrinsics) => rust_features.x86_amx_intrinsics, Some(sym::xop_target_feature) => rust_features.xop_target_feature, + Some(sym::s390x_target_feature) => rust_features.s390x_target_feature, Some(name) => bug!("unknown target feature gate {}", name), None => true, }; diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 523d55fe2d0..8700ec4c210 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; use rustc_middle::ty::{Instance, InstanceKind, TypeVisitableExt}; use rustc_mir_dataflow::Analysis; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt}; use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor}; diff --git a/compiler/rustc_error_codes/src/error_codes/E0771.md b/compiler/rustc_error_codes/src/error_codes/E0771.md index 4f36590025b..74149eb79f6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0771.md +++ b/compiler/rustc_error_codes/src/error_codes/E0771.md @@ -6,7 +6,7 @@ allowed. Erroneous code example: ```compile_fail,E0770 -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] fn function_with_str<'a, const STRING: &'a str>() {} // error! ``` @@ -15,7 +15,7 @@ To fix this issue, the lifetime in the const generic need to be changed to `'static`: ``` -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] fn function_with_str<const STRING: &'static str>() {} // ok! ``` diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 56ef609612a..4b730d307fd 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -352,10 +352,10 @@ fn check_occurrences( check_ops_is_prefix(psess, node_id, macros, binders, ops, span, name); } TokenTree::MetaVarExpr(dl, ref mve) => { - let Some(name) = mve.ident().map(MacroRulesNormalizedIdent::new) else { - return; - }; - check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name); + mve.for_each_metavar((), |_, ident| { + let name = MacroRulesNormalizedIdent::new(*ident); + check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name); + }); } TokenTree::Delimited(.., ref del) => { check_nested_occurrences(psess, node_id, &del.tts, macros, binders, ops, guar); diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 2964ac8cc58..c4ba98f581e 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -111,10 +111,18 @@ impl MetaVarExpr { Ok(rslt) } - pub(crate) fn ident(&self) -> Option<Ident> { - match *self { - MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident), - MetaVarExpr::Concat { .. } | MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None, + pub(crate) fn for_each_metavar<A>(&self, mut aux: A, mut cb: impl FnMut(A, &Ident) -> A) -> A { + match self { + MetaVarExpr::Concat(elems) => { + for elem in elems { + if let MetaVarExprConcatElem::Var(ident) = elem { + aux = cb(aux, ident) + } + } + aux + } + MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => cb(aux, ident), + MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => aux, } } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 7e2ea8de5fc..62337756cd8 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -557,17 +557,13 @@ fn lockstep_iter_size( } } TokenTree::MetaVarExpr(_, expr) => { - let default_rslt = LockstepIterSize::Unconstrained; - let Some(ident) = expr.ident() else { - return default_rslt; - }; - let name = MacroRulesNormalizedIdent::new(ident); - match lookup_cur_matched(name, interpolations, repeats) { - Some(MatchedSeq(ads)) => { - default_rslt.with(LockstepIterSize::Constraint(ads.len(), name)) - } - _ => default_rslt, - } + expr.for_each_metavar(LockstepIterSize::Unconstrained, |lis, ident| { + lis.with(lockstep_iter_size( + &TokenTree::MetaVar(ident.span, *ident), + interpolations, + repeats, + )) + }) } TokenTree::Token(..) => LockstepIterSize::Unconstrained, } @@ -695,7 +691,23 @@ fn transcribe_metavar_expr<'a>( let symbol = match element { MetaVarExprConcatElem::Ident(elem) => elem.name, MetaVarExprConcatElem::Literal(elem) => *elem, - MetaVarExprConcatElem::Var(elem) => extract_var_symbol(dcx, *elem, interp)?, + MetaVarExprConcatElem::Var(ident) => { + match matched_from_ident(dcx, *ident, interp)? { + NamedMatch::MatchedSeq(named_matches) => { + let curr_idx = repeats.last().unwrap().0; + match &named_matches[curr_idx] { + // FIXME(c410-f3r) Nested repetitions are unimplemented + MatchedSeq(_) => unimplemented!(), + MatchedSingle(pnr) => { + extract_symbol_from_pnr(dcx, pnr, ident.span)? + } + } + } + NamedMatch::MatchedSingle(pnr) => { + extract_symbol_from_pnr(dcx, pnr, ident.span)? + } + } + } }; concatenated.push_str(symbol.as_str()); } @@ -752,41 +764,48 @@ fn transcribe_metavar_expr<'a>( } /// Extracts an metavariable symbol that can be an identifier, a token tree or a literal. -fn extract_var_symbol<'a>( +fn extract_symbol_from_pnr<'a>( dcx: DiagCtxtHandle<'a>, - ident: Ident, - interp: &FxHashMap<MacroRulesNormalizedIdent, NamedMatch>, + pnr: &ParseNtResult, + span_err: Span, ) -> PResult<'a, Symbol> { - if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? { - if let ParseNtResult::Ident(nt_ident, is_raw) = pnr { + match pnr { + ParseNtResult::Ident(nt_ident, is_raw) => { if let IdentIsRaw::Yes = is_raw { - return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); + return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR)); } return Ok(nt_ident.name); } - - if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr { - if let TokenKind::Ident(symbol, is_raw) = kind { - if let IdentIsRaw::Yes = is_raw { - return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); - } - return Ok(*symbol); - } - - if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind { - return Ok(*symbol); + ParseNtResult::Tt(TokenTree::Token( + Token { kind: TokenKind::Ident(symbol, is_raw), .. }, + _, + )) => { + if let IdentIsRaw::Yes = is_raw { + return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR)); } + return Ok(*symbol); } - - if let ParseNtResult::Nt(nt) = pnr - && let Nonterminal::NtLiteral(expr) = &**nt - && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind + ParseNtResult::Tt(TokenTree::Token( + Token { + kind: TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }), + .. + }, + _, + )) => { + return Ok(*symbol); + } + ParseNtResult::Nt(nt) + if let Nonterminal::NtLiteral(expr) = &**nt + && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = + &expr.kind => { return Ok(*symbol); } + _ => Err(dcx + .struct_err( + "metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`", + ) + .with_note("currently only string literals are supported") + .with_span(span_err)), } - Err(dcx - .struct_err("metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`") - .with_note("currently only string literals are supported") - .with_span(ident.span)) } diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index 1db3774222a..9b5ed3b0876 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -312,6 +312,7 @@ declare_features! ( (unstable, prfchw_target_feature, "1.78.0", Some(44839)), (unstable, riscv_target_feature, "1.45.0", Some(44839)), (unstable, rtm_target_feature, "1.35.0", Some(44839)), + (unstable, s390x_target_feature, "CURRENT_RUSTC_VERSION", Some(44839)), (unstable, sse4a_target_feature, "1.27.0", Some(44839)), (unstable, tbm_target_feature, "1.27.0", Some(44839)), (unstable, wasm_target_feature, "1.30.0", Some(44839)), @@ -339,8 +340,8 @@ declare_features! ( (unstable, abi_riscv_interrupt, "1.73.0", Some(111889)), /// Allows `extern "x86-interrupt" fn()`. (unstable, abi_x86_interrupt, "1.17.0", Some(40180)), - /// Allows additional const parameter types, such as `&'static str` or user defined types - (incomplete, adt_const_params, "1.56.0", Some(95174)), + /// Allows additional const parameter types, such as `[u8; 10]` or user defined types + (unstable, adt_const_params, "1.56.0", Some(95174)), /// Allows defining an `#[alloc_error_handler]`. (unstable, alloc_error_handler, "1.29.0", Some(51540)), /// Allows trait methods with arbitrary self types. @@ -630,6 +631,9 @@ declare_features! ( (unstable, unsafe_attributes, "1.80.0", Some(123757)), /// Allows unsafe on extern declarations and safety qualifiers over internal items. (unstable, unsafe_extern_blocks, "1.80.0", Some(123743)), + /// Allows const generic parameters to be defined with types that + /// are not `Sized`, e.g. `fn foo<const N: [u8]>() {`. + (incomplete, unsized_const_params, "CURRENT_RUSTC_VERSION", Some(95174)), /// Allows unsized fn parameters. (internal, unsized_fn_params, "1.49.0", Some(48055)), /// Allows unsized rvalues at arguments and parameters. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 30c0e40206a..58cc0f62111 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -358,6 +358,7 @@ language_item_table! { PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0); ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); + UnsizedConstParamTy, sym::unsized_const_param_ty, unsized_const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None; PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index f08a0f8c8fc..cc404daa51f 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -99,6 +99,10 @@ hir_analysis_const_param_ty_impl_on_non_adt = the trait `ConstParamTy` may not be implemented for this type .label = type is not a structure or enumeration +hir_analysis_const_param_ty_impl_on_unsized = + the trait `ConstParamTy` may not be implemented for this type + .label = type is not `Sized` + hir_analysis_const_specialize = cannot specialize on const impl with non-const impl hir_analysis_copy_impl_on_non_adt = diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index dbc265ad3ff..27db5418165 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -26,7 +26,7 @@ use rustc_middle::ty::{ use rustc_session::lint::builtin::{UNINHABITED_STATIC, UNSUPPORTED_CALLING_CONVENTIONS}; use rustc_target::abi::FieldIdx; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedDirective; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_type_ir::fold::TypeFoldable; diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 6c53625b590..c99f13468e2 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::{ use rustc_middle::ty::{GenericParamDefKind, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_span::Span; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index ce921f64481..e4d4b7df24e 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -7,7 +7,7 @@ use rustc_session::config::EntryFnType; use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID}; use rustc_span::{symbol::sym, Span}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; use std::ops::Not; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 24aeb024461..4c230ad84de 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -82,7 +82,6 @@ use rustc_errors::{pluralize, struct_span_code_err, Diag}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; -use rustc_infer::error_reporting::infer::ObligationCauseExt as _; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{self, TyCtxtInferExt as _}; use rustc_infer::traits::ObligationCause; @@ -96,10 +95,9 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::suggestions::{ - ReturnsVisitor, TypeErrCtxtExt as _, -}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::infer::ObligationCauseExt as _; +use rustc_trait_selection::error_reporting::traits::suggestions::ReturnsVisitor; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::ObligationCtxt; use crate::errors; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 71a7b0b1638..0316ef69bf8 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -29,7 +29,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::regions::InferCtxtRegionExt; use rustc_trait_selection::traits::misc::{ type_allowed_to_implement_const_param_ty, ConstParamTyImplementationError, @@ -922,10 +922,8 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), } => { let ty = tcx.type_of(param.def_id).instantiate_identity(); - if tcx.features().adt_const_params { + if tcx.features().unsized_const_params { enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { - let trait_def_id = - tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)); wfcx.register_bound( ObligationCause::new( hir_ty.span, @@ -934,7 +932,21 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), ), wfcx.param_env, ty, - trait_def_id, + tcx.require_lang_item(LangItem::UnsizedConstParamTy, Some(hir_ty.span)), + ); + Ok(()) + }) + } else if tcx.features().adt_const_params { + enter_wf_checking_ctxt(tcx, hir_ty.span, param.def_id, |wfcx| { + wfcx.register_bound( + ObligationCause::new( + hir_ty.span, + param.def_id, + ObligationCauseCode::ConstParam(ty), + ), + wfcx.param_env, + ty, + tcx.require_lang_item(LangItem::ConstParamTy, Some(hir_ty.span)), ); Ok(()) }) @@ -958,14 +970,29 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), diag.note("the only supported types are integers, `bool` and `char`"); let cause = ObligationCause::misc(hir_ty.span, param.def_id); + let adt_const_params_feature_string = + " more complex and user defined types".to_string(); let may_suggest_feature = match type_allowed_to_implement_const_param_ty( tcx, tcx.param_env(param.def_id), ty, + LangItem::ConstParamTy, cause, ) { // Can never implement `ConstParamTy`, don't suggest anything. - Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => false, + Err( + ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed + | ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(..), + ) => None, + Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => { + Some(vec![ + (adt_const_params_feature_string, sym::adt_const_params), + ( + " references to implement the `ConstParamTy` trait".into(), + sym::unsized_const_params, + ), + ]) + } // May be able to implement `ConstParamTy`. Only emit the feature help // if the type is local, since the user may be able to fix the local type. Err(ConstParamTyImplementationError::InfrigingFields(..)) => { @@ -985,20 +1012,16 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(), } } - ty_is_local(ty) + ty_is_local(ty).then_some(vec![( + adt_const_params_feature_string, + sym::adt_const_params, + )]) } // Implments `ConstParamTy`, suggest adding the feature to enable. - Ok(..) => true, + Ok(..) => Some(vec![(adt_const_params_feature_string, sym::adt_const_params)]), }; - if may_suggest_feature { - tcx.disabled_nightly_features( - &mut diag, - Some(param.hir_id), - [( - " more complex and user defined types".to_string(), - sym::adt_const_params, - )], - ); + if let Some(features) = may_suggest_feature { + tcx.disabled_nightly_features(&mut diag, Some(param.hir_id), features); } Err(diag.emit()) diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 2ecb170ec89..b35ee270fef 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::adjustment::CoerceUnsizedInfo; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::{Span, DUMMY_SP}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::misc::{ type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy, ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason, @@ -36,9 +36,13 @@ pub(super) fn check_trait<'tcx>( let checker = Checker { tcx, trait_def_id, impl_def_id, impl_header }; let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop); res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy)); - res = res.and( - checker.check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty), - ); + res = res.and(checker.check(lang_items.const_param_ty_trait(), |checker| { + visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy) + })); + res = res.and(checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { + visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy) + })); + res = res.and( checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized), ); @@ -103,7 +107,13 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran Ok(()) => Ok(()), Err(CopyImplementationError::InfringingFields(fields)) => { let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; - Err(infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span)) + Err(infringing_fields_error( + tcx, + fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)), + LangItem::Copy, + impl_did, + span, + )) } Err(CopyImplementationError::NotAnAdt) => { let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; @@ -116,7 +126,12 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran } } -fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { +fn visit_implementation_of_const_param_ty( + checker: &Checker<'_>, + kind: LangItem, +) -> Result<(), ErrorGuaranteed> { + assert!(matches!(kind, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy)); + let tcx = checker.tcx; let header = checker.impl_header; let impl_did = checker.impl_def_id; @@ -125,21 +140,41 @@ fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), E let param_env = tcx.param_env(impl_did); - if let ty::ImplPolarity::Negative = header.polarity { + if let ty::ImplPolarity::Negative | ty::ImplPolarity::Reservation = header.polarity { return Ok(()); } let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did); - match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) { + match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, kind, cause) { Ok(()) => Ok(()), Err(ConstParamTyImplementationError::InfrigingFields(fields)) => { let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; - Err(infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span)) + Err(infringing_fields_error( + tcx, + fields.into_iter().map(|(field, ty, reason)| (tcx.def_span(field.did), ty, reason)), + LangItem::ConstParamTy, + impl_did, + span, + )) } Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => { let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span })) } + Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy(infringing_tys)) => { + let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + Err(infringing_fields_error( + tcx, + infringing_tys.into_iter().map(|(ty, reason)| (span, ty, reason)), + LangItem::ConstParamTy, + impl_did, + span, + )) + } + Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired) => { + let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span; + Err(tcx.dcx().emit_err(errors::ConstParamTyImplOnUnsized { span })) + } } } @@ -501,9 +536,9 @@ pub fn coerce_unsized_info<'tcx>( Ok(CoerceUnsizedInfo { custom_kind: kind }) } -fn infringing_fields_error( - tcx: TyCtxt<'_>, - fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>, +fn infringing_fields_error<'tcx>( + tcx: TyCtxt<'tcx>, + infringing_tys: impl Iterator<Item = (Span, Ty<'tcx>, InfringingFieldsReason<'tcx>)>, lang_item: LangItem, impl_did: LocalDefId, impl_span: Span, @@ -521,13 +556,13 @@ fn infringing_fields_error( let mut label_spans = Vec::new(); - for (field, ty, reason) in fields { + for (span, ty, reason) in infringing_tys { // Only report an error once per type. if !seen_tys.insert(ty) { continue; } - label_spans.push(tcx.def_span(field.did)); + label_spans.push(span); match reason { InfringingFieldsReason::Fulfill(fulfillment_errors) => { diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 16f72f38d60..f2804ce31fa 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -517,9 +517,10 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for UncoveredTyParamCollector<'_, 'tcx> { if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) { return; } - let Some(origin) = self.infcx.type_var_origin(ty) else { + let ty::Infer(ty::TyVar(vid)) = *ty.kind() else { return ty.super_visit_with(self); }; + let origin = self.infcx.type_var_origin(vid); if let Some(def_id) = origin.param_def_id { self.uncovered_params.insert(def_id); } @@ -546,9 +547,10 @@ impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for TyVarReplacer<'cx, 'tcx> { if !ty.has_type_flags(ty::TypeFlags::HAS_TY_INFER) { return ty; } - let Some(origin) = self.infcx.type_var_origin(ty) else { + let ty::Infer(ty::TyVar(vid)) = *ty.kind() else { return ty.super_fold_with(self); }; + let origin = self.infcx.type_var_origin(vid); if let Some(def_id) = origin.param_def_id { // The generics of an `impl` don't have a parent, we can index directly. let index = self.generics.param_def_id_to_index[&def_id]; diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 7930f54038d..349dc9ad00e 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -2094,11 +2094,7 @@ pub fn deny_non_region_late_bound( format!("late-bound {what} parameter not allowed on {where_}"), ); - let guar = if tcx.features().non_lifetime_binders && first { - diag.emit() - } else { - diag.delay_as_bug() - }; + let guar = diag.emit_unless(!tcx.features().non_lifetime_binders || !first); first = false; *arg = ResolvedArg::Error(guar); diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index 2eca64c27d0..c83788928a9 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -279,6 +279,14 @@ pub struct CopyImplOnNonAdt { } #[derive(Diagnostic)] +#[diag(hir_analysis_const_param_ty_impl_on_unsized)] +pub struct ConstParamTyImplOnUnsized { + #[primary_span] + #[label] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(hir_analysis_const_param_ty_impl_on_non_adt)] pub struct ConstParamTyImplOnNonAdt { #[primary_span] diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 5b8b6e98125..2e5f99bb78b 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -78,7 +78,7 @@ use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArg, GenericArgs, GenericArgsRef}; use rustc_span::{ErrorGuaranteed, Span}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; use rustc_trait_selection::traits::{self, translate_args_with_cause, wf, ObligationCtxt}; diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index 5e2a68e1f02..1bfe9734217 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -58,8 +58,6 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{BytePos, DesugaringKind, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtSelectionErrExt as _; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::{ diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index d708269f1f5..0d002c52fbb 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -53,8 +53,6 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use rustc_target::abi::{FieldIdx, FIRST_VARIANT}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCauseCode}; @@ -2574,7 +2572,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base: &'tcx hir::Expr<'tcx>, ty: Ty<'tcx>, ) { - let Some(output_ty) = self.get_impl_future_output_ty(ty) else { + let Some(output_ty) = self.err_ctxt().get_impl_future_output_ty(ty) else { err.span_label(field_ident.span, "unknown field"); return; }; diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs index 3cecbfd4275..9f3aeacd2c5 100644 --- a/compiler/rustc_hir_typeck/src/fallback.rs +++ b/compiler/rustc_hir_typeck/src/fallback.rs @@ -175,7 +175,7 @@ impl<'tcx> FnCtxt<'_, 'tcx> { }; debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback); - let span = self.infcx.type_var_origin(ty).map(|origin| origin.span).unwrap_or(DUMMY_SP); + let span = ty.ty_vid().map_or(DUMMY_SP, |vid| self.infcx.type_var_origin(vid).span); self.demand_eqtype(span, ty, fallback); self.fallback_has_occurred.set(true); true diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index cc2c1a302f5..87e8afe6dd1 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -19,7 +19,6 @@ use rustc_hir_analysis::hir_ty_lowering::{ GenericPathSegment, HirTyLowerer, IsMethodCall, RegionInferReason, }; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::{DefineOpaqueTypes, InferResult}; use rustc_lint::builtin::SELF_CONSTRUCTOR_FROM_OUTER_ITEM; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; @@ -37,7 +36,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::symbol::{kw, sym}; use rustc_span::Span; use rustc_target::abi::FieldIdx; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::traits::{ self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt, }; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index f7abba35706..8e35efa53ae 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -338,8 +338,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for FindAmbiguousParameter<'_, 'tcx> { type Result = ControlFlow<ty::GenericArg<'tcx>>; fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { - if let Some(origin) = self.0.type_var_origin(ty) - && let Some(def_id) = origin.param_def_id + if let ty::Infer(ty::TyVar(vid)) = *ty.kind() + && let Some(def_id) = self.0.type_var_origin(vid).param_def_id && let generics = self.0.tcx.generics_of(self.1) && let Some(index) = generics.param_def_id_to_index(self.0.tcx, def_id) && let Some(arg) = diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 2b4025ca808..7c96a991bed 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -29,7 +29,6 @@ use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer; use rustc_index::IndexVec; -use rustc_infer::error_reporting::infer::{FailureCode, ObligationCauseExt}; use rustc_infer::infer::TypeTrace; use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::ty::adjustment::AllowTwoPhase; @@ -39,6 +38,7 @@ use rustc_middle::{bug, span_bug}; use rustc_session::Session; use rustc_span::symbol::{kw, Ident}; use rustc_span::{sym, BytePos, Span, DUMMY_SP}; +use rustc_trait_selection::error_reporting::infer::{FailureCode, ObligationCauseExt}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 3fe87c03e74..39d73dae015 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -15,13 +15,13 @@ use hir::def_id::CRATE_DEF_ID; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, RegionInferReason}; -use rustc_infer::error_reporting::infer::sub_relations::SubRelations; -use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer; use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::{self, sym, Span, DUMMY_SP}; +use rustc_trait_selection::error_reporting::infer::sub_relations::SubRelations; +use rustc_trait_selection::error_reporting::TypeErrCtxt; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt}; use std::cell::{Cell, RefCell}; @@ -162,9 +162,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Creates an `TypeErrCtxt` with a reference to the in-progress /// `TypeckResults` which is used for diagnostics. - /// Use [`InferCtxt::err_ctxt`] to start one without a `TypeckResults`. + /// Use [`InferCtxtErrorExt::err_ctxt`] to start one without a `TypeckResults`. /// - /// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt + /// [`InferCtxtErrorExt::err_ctxt`]: rustc_trait_selection::error_reporting::InferCtxtErrorExt::err_ctxt pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> { let mut sub_relations = SubRelations::default(); sub_relations.add_constraints( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index b3b4c5a56fb..fe7495deb2b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -32,8 +32,8 @@ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::{Span, Symbol}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; use rustc_trait_selection::error_reporting::traits::DefIdOrName; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; @@ -1107,12 +1107,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .tcx .instantiate_bound_regions_with_erased(Binder::bind_with_vars(ty, bound_vars)); let ty = match self.tcx.asyncness(fn_id) { - ty::Asyncness::Yes => self.get_impl_future_output_ty(ty).unwrap_or_else(|| { - span_bug!( - fn_decl.output.span(), - "failed to get output type of async function" - ) - }), + ty::Asyncness::Yes => { + self.err_ctxt().get_impl_future_output_ty(ty).unwrap_or_else(|| { + span_bug!( + fn_decl.output.span(), + "failed to get output type of async function" + ) + }) + } ty::Asyncness::No => ty, }; let ty = self.normalize(expr.span, ty); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index e817685e41c..9cb6124ab21 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -12,7 +12,6 @@ use rustc_hir::HirId; use rustc_hir_analysis::autoderef::{self, Autoderef}; use rustc_infer::infer::canonical::OriginalQueryValues; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; -use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_infer::traits::ObligationCauseCode; @@ -34,6 +33,7 @@ use rustc_span::edit_distance::{ }; use rustc_span::symbol::sym; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::infer::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 9bb30780a6e..da3ac2fea98 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -36,7 +36,6 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{edit_distance, ErrorGuaranteed, ExpnKind, FileName, MacroKind, Span}; use rustc_span::{Symbol, DUMMY_SP}; use rustc_trait_selection::error_reporting::traits::on_unimplemented::OnUnimplementedNote; -use rustc_trait_selection::error_reporting::traits::on_unimplemented::TypeErrCtxtExt as _; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ @@ -3276,7 +3275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, return_type: Option<Ty<'tcx>>, ) { - let output_ty = match self.get_impl_future_output_ty(ty) { + let output_ty = match self.err_ctxt().get_impl_future_output_ty(ty) { Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs index d59b8276d3a..7b5845388d4 100644 --- a/compiler/rustc_hir_typeck/src/op.rs +++ b/compiler/rustc_hir_typeck/src/op.rs @@ -18,7 +18,6 @@ use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt as _; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt}; use rustc_type_ir::TyKind::*; diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 611854ce2af..4ef7f37b309 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -8,7 +8,6 @@ use rustc_errors::{ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::HirId; -use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_middle::span_bug; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; @@ -18,7 +17,7 @@ use rustc_middle::ty::TypeSuperFoldable; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::symbol::sym; use rustc_span::Span; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; use rustc_trait_selection::solve; use std::mem; diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl index c279195a7e9..e51734ff7a7 100644 --- a/compiler/rustc_infer/messages.ftl +++ b/compiler/rustc_infer/messages.ftl @@ -1,397 +1,5 @@ -infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime -> - [true] , for some specific lifetime `'{$lifetime}` - *[false] {""} -} -infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime -> - [true] , for some specific lifetime `'{$lifetime}` - *[false] {""} -} -infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime -> - [true] , for some specific lifetime `'{$lifetime}` - *[false] {""} -} - -infer_actual_impl_expl_expected_other_any = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}` - -infer_actual_impl_expl_expected_other_some = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_other_two = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... -infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}` -infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis -> - [true] ... - *[false] {""} -}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... -infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis -> - [true] ... - *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis -> - [true] ... - *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}` -infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis -> - [true] ... - *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... -infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis -> - [true] ... - *[false] {""} -}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... -infer_ascribe_user_type_prove_predicate = ...so that the where clause holds - -infer_await_both_futures = consider `await`ing on both `Future`s -infer_await_future = consider `await`ing on the `Future` -infer_await_note = calling an async function returns a future - -infer_but_calling_introduces = {$has_param_name -> - [true] `{$param_name}` - *[false] `fn` parameter -} has {$lifetime_kind -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` -} but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement - .label1 = {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` - } - .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path -> - [true] `impl` of `{$impl_path}` - *[false] inherent `impl` - } - -infer_but_needs_to_satisfy = {$has_param_name -> - [true] `{$param_name}` - *[false] `fn` parameter -} has {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` -} but it needs to satisfy a `'static` lifetime requirement - .influencer = this data with {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` - }... - .require = {$spans_empty -> - *[true] ...is used and required to live as long as `'static` here - [false] ...and is required to live as long as `'static` here - } - .used_here = ...is used here... - .introduced_by_bound = `'static` lifetime requirement introduced by this bound - -infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait -infer_consider_specifying_length = consider specifying the actual array length -infer_data_flows = ...but data{$label_var1_exists -> - [true] {" "}from `{$label_var1}` - *[false] {""} -} flows{$label_var2_exists -> - [true] {" "}into `{$label_var2}` - *[false] {""} -} here - -infer_data_lifetime_flow = ...but data with one lifetime flows into the other here -infer_data_returned = ...but data{$label_var1_exists -> - [true] {" "}from `{$label_var1}` - *[false] {""} -} is returned here - -infer_declared_different = this parameter and the return type are declared with different lifetimes... -infer_declared_multiple = this type is declared with multiple lifetimes... -infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` -infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement -infer_dtcs_has_req_note = the used `impl` has a `'static` requirement -infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement -infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement - -infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` - -infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type - -infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}` - .label = lifetime `{$named}` required - -infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type - .label = lifetime `{$named}` required - -infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}` - -infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same -infer_fps_cast = consider casting to a fn pointer -infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}` - -infer_fps_items_are_distinct = fn items are distinct from fn pointers -infer_fps_remove_ref = consider removing the reference -infer_fps_use_ref = consider using a reference -infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime - -infer_full_type_written = the full type name has been written to '{$path}' - -infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement -infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement -infer_label_bad = {$bad_kind -> - *[other] cannot infer type - [more_info] cannot infer {$prefix_kind -> - *[type] type for {$prefix} - [const_with_param] the value of const parameter - [const] the value of the constant - } `{$name}`{$has_parent -> - [true] {" "}declared on the {$parent_prefix} `{$parent_name}` - *[false] {""} - } -} - -infer_lf_bound_not_satisfied = lifetime bound not satisfied -infer_lifetime_mismatch = lifetime mismatch - -infer_lifetime_param_suggestion = consider {$is_reuse -> - [true] reusing - *[false] introducing -} a named lifetime parameter{$is_impl -> - [true] {" "}and update trait if needed - *[false] {""} -} -infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime - -infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b` -infer_meant_char_literal = if you meant to write a `char` literal, use single quotes -infer_meant_str_literal = if you meant to write a string literal, use double quotes -infer_mismatched_static_lifetime = incompatible lifetime on type -infer_more_targeted = {$has_param_name -> - [true] `{$param_name}` - *[false] `fn` parameter -} has {$has_lifetime -> - [true] lifetime `{$lifetime}` - *[false] an anonymous lifetime `'_` -} but calling `{$ident}` introduces an implicit `'static` lifetime requirement - -infer_msl_introduces_static = introduces a `'static` lifetime requirement -infer_msl_unmet_req = because this has an unmet lifetime requirement - -infer_nothing = {""} - -infer_oc_cant_coerce = cannot coerce intrinsics to function pointers -infer_oc_closure_selfref = closure/coroutine type that references itself -infer_oc_const_compat = const not compatible with trait -infer_oc_fn_lang_correct_type = {$lang_item_name -> - [panic_impl] `#[panic_handler]` - *[lang_item_name] lang item `{$lang_item_name}` - } function has wrong type -infer_oc_fn_main_correct_type = `main` function has wrong type -infer_oc_fn_start_correct_type = `#[start]` function has wrong type -infer_oc_generic = mismatched types - -infer_oc_if_else_different = `if` and `else` have incompatible types -infer_oc_intrinsic_correct_type = intrinsic has wrong type -infer_oc_match_compat = `match` arms have incompatible types -infer_oc_method_compat = method not compatible with trait -infer_oc_method_correct_type = mismatched `self` parameter type -infer_oc_no_diverge = `else` clause of `let...else` does not diverge -infer_oc_no_else = `if` may be missing an `else` clause -infer_oc_try_compat = `?` operator has incompatible types -infer_oc_type_compat = type not compatible with trait -infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds - .label = opaque type defined here - infer_opaque_hidden_type = opaque type's hidden type cannot be another opaque type from the same scope .label = one of the two opaque types used here has to be outside its defining scope .opaque_type = opaque type whose hidden type is being assigned .hidden_type = opaque type being used as hidden type - -infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type -infer_outlives_content = lifetime of reference outlives lifetime of borrowed content... - -infer_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it -infer_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` - -infer_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate - -infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... -infer_prlf_defined_without_sub = the lifetime defined here... -infer_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information) - -infer_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here -infer_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here -infer_reborrow = ...so that reference does not outlive borrowed content -infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references - -infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at -infer_region_explanation = {$pref_kind -> - *[should_not_happen] [{$pref_kind}] - [ref_valid_for] ...the reference is valid for - [content_valid_for] ...but the borrowed content is only valid for - [type_obj_valid_for] object type is valid for - [source_pointer_valid_for] source pointer is only valid for - [type_satisfy] type must satisfy - [type_outlive] type must outlive - [lf_param_instantiated_with] lifetime parameter instantiated with - [lf_param_must_outlive] but lifetime parameter must outlive - [lf_instantiated_with] lifetime instantiated with - [lf_must_outlive] but lifetime must outlive - [pointer_valid_for] the pointer is valid for - [data_valid_for] but the referenced data is only valid for - [empty] {""} -}{$pref_kind -> - [empty] {""} - *[other] {" "} -}{$desc_kind -> - *[should_not_happen] [{$desc_kind}] - [restatic] the static lifetime - [revar] lifetime {$desc_arg} - [as_defined] the lifetime `{$desc_arg}` as defined here - [as_defined_anon] the anonymous lifetime as defined here - [defined_here] the anonymous lifetime defined here - [defined_here_reg] the lifetime `{$desc_arg}` as defined here -}{$suff_kind -> - *[should_not_happen] [{$suff_kind}] - [empty]{""} - [continues] ... - [req_by_binding] {" "}as required by this binding -} - -infer_relate_object_bound = ...so that it can be closed over into an object -infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> - [true] ... - *[false] {""} -} -infer_relate_param_bound_2 = ...that is required by this bound -infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied -infer_ril_because_of = because of this returned expression -infer_ril_introduced_by = requirement introduced by this return type -infer_ril_introduced_here = `'static` requirement introduced here -infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type - -infer_source_kind_closure_return = - try giving this closure an explicit return type - -# coroutine_kind may need to be translated -infer_source_kind_fully_qualified = - try using a fully qualified path to specify the expected types - -infer_source_kind_subdiag_generic_label = - cannot infer {$is_type -> - [true] type - *[false] the value - } of the {$is_type -> - [true] type - *[false] const - } {$parent_exists -> - [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` - *[false] parameter {$param_name} - } - -infer_source_kind_subdiag_generic_suggestion = - consider specifying the generic {$arg_count -> - [one] argument - *[other] arguments - } - -infer_source_kind_subdiag_let = {$kind -> - [with_pattern] consider giving `{$name}` an explicit type - [closure] consider giving this closure parameter an explicit type - *[other] consider giving this pattern a type -}{$x_kind -> - [has_name] , where the {$prefix_kind -> - *[type] type for {$prefix} - [const_with_param] value of const parameter - [const] value of the constant - } `{$arg_name}` is specified - [underscore] , where the placeholders `_` are specified - *[empty] {""} -} - -infer_srs_add = consider returning the local binding `{$ident}` -infer_srs_add_one = consider returning one of these bindings - -infer_srs_remove = consider removing this semicolon -infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions -infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}` - -infer_stp_wrap_one = try wrapping the pattern in `{$variant}` -infer_subtype = ...so that the {$requirement -> - [method_compat] method type is compatible with trait - [type_compat] associated type is compatible with trait - [const_compat] const is compatible with trait - [expr_assignable] expression is assignable - [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 - *[other] types are compatible -} -infer_subtype_2 = ...so that {$requirement -> - [method_compat] method type is compatible with trait - [type_compat] associated type is compatible with trait - [const_compat] const is compatible with trait - [expr_assignable] expression is assignable - [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 - *[other] types are compatible -} - -infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}` - -infer_suggest_add_let_for_letchains = consider adding `let` - -infer_tid_consider_borrowing = consider borrowing this type parameter in the trait -infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` - -infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output -infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature - .found = found `{$found}` - .expected = expected `{$expected}` - .expected_found = expected signature `{$expected}` - {" "}found signature `{$found}` - -infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough - .label_satisfy = doesn't satisfy where-clause - .label_where = due to a where-clause on `{$def_id}`... - .label_dup = implementation of `{$trait_def_id}` is not general enough - -infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}` - -infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element - -infer_type_annotations_needed = {$source_kind -> - [closure] type annotations needed for the closure `{$source_name}` - [normal] type annotations needed for `{$source_name}` - *[other] type annotations needed -} - .label = type must be known at this point - -infer_types_declared_different = these two types are declared with different lifetimes... - -infer_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable - -infer_where_copy_predicates = copy the `where` clause predicates from the trait - -infer_where_remove = remove the `where` clause diff --git a/compiler/rustc_infer/src/error_reporting/mod.rs b/compiler/rustc_infer/src/error_reporting/mod.rs deleted file mode 100644 index 132485ec661..00000000000 --- a/compiler/rustc_infer/src/error_reporting/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod infer; diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 2ce712e0bff..1a5c0137219 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -1,28 +1,5 @@ -use hir::GenericParamKind; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{ - codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg, - MultiSpan, SubdiagMessageOp, Subdiagnostic, -}; -use rustc_hir as hir; -use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{walk_ty, Visitor}; -use rustc_hir::FnRetTy; -use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath; -use rustc_middle::ty::{Binder, FnSig, Region, Ty, TyCtxt}; -use rustc_span::symbol::kw; -use rustc_span::Symbol; -use rustc_span::{symbol::Ident, BytePos, Span}; - -use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted; -use crate::error_reporting::infer::ObligationCauseAsDiagArg; -use crate::fluent_generated as fluent; -use crate::infer::need_type_info::UnderspecifiedArgKind; - -use std::path::PathBuf; - -pub mod note_and_explain; +use rustc_macros::Diagnostic; +use rustc_span::Span; #[derive(Diagnostic)] #[diag(infer_opaque_hidden_type)] @@ -35,1599 +12,3 @@ pub struct OpaqueHiddenTypeDiag { #[note(infer_hidden_type)] pub hidden_type: Span, } - -#[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = E0282)] -pub struct AnnotationRequired<'a> { - #[primary_span] - pub span: Span, - pub source_kind: &'static str, - pub source_name: &'a str, - #[label] - pub failure_span: Option<Span>, - #[subdiagnostic] - pub bad_label: Option<InferenceBadError<'a>>, - #[subdiagnostic] - pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, - #[subdiagnostic] - pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, - #[note(infer_full_type_written)] - pub was_written: Option<()>, - pub path: PathBuf, -} - -// Copy of `AnnotationRequired` for E0283 -#[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = E0283)] -pub struct AmbiguousImpl<'a> { - #[primary_span] - pub span: Span, - pub source_kind: &'static str, - pub source_name: &'a str, - #[label] - pub failure_span: Option<Span>, - #[subdiagnostic] - pub bad_label: Option<InferenceBadError<'a>>, - #[subdiagnostic] - pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, - #[subdiagnostic] - pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, - #[note(infer_full_type_written)] - pub was_written: Option<()>, - pub path: PathBuf, -} - -// Copy of `AnnotationRequired` for E0284 -#[derive(Diagnostic)] -#[diag(infer_type_annotations_needed, code = E0284)] -pub struct AmbiguousReturn<'a> { - #[primary_span] - pub span: Span, - pub source_kind: &'static str, - pub source_name: &'a str, - #[label] - pub failure_span: Option<Span>, - #[subdiagnostic] - pub bad_label: Option<InferenceBadError<'a>>, - #[subdiagnostic] - pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, - #[subdiagnostic] - pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, - #[note(infer_full_type_written)] - pub was_written: Option<()>, - pub path: PathBuf, -} - -// Used when a better one isn't available -#[derive(Subdiagnostic)] -#[label(infer_label_bad)] -pub struct InferenceBadError<'a> { - #[primary_span] - pub span: Span, - pub bad_kind: &'static str, - pub prefix_kind: UnderspecifiedArgKind, - pub has_parent: bool, - pub prefix: &'a str, - pub parent_prefix: &'a str, - pub parent_name: String, - pub name: String, -} - -#[derive(Subdiagnostic)] -pub enum SourceKindSubdiag<'a> { - #[suggestion( - infer_source_kind_subdiag_let, - style = "verbose", - code = ": {type_name}", - applicability = "has-placeholders" - )] - LetLike { - #[primary_span] - span: Span, - name: String, - type_name: String, - kind: &'static str, - x_kind: &'static str, - prefix_kind: UnderspecifiedArgKind, - prefix: &'a str, - arg_name: String, - }, - #[label(infer_source_kind_subdiag_generic_label)] - GenericLabel { - #[primary_span] - span: Span, - is_type: bool, - param_name: String, - parent_exists: bool, - parent_prefix: String, - parent_name: String, - }, - #[suggestion( - infer_source_kind_subdiag_generic_suggestion, - style = "verbose", - code = "::<{args}>", - applicability = "has-placeholders" - )] - GenericSuggestion { - #[primary_span] - span: Span, - arg_count: usize, - args: String, - }, -} - -#[derive(Subdiagnostic)] -pub enum SourceKindMultiSuggestion<'a> { - #[multipart_suggestion( - infer_source_kind_fully_qualified, - style = "verbose", - applicability = "has-placeholders" - )] - FullyQualified { - #[suggestion_part(code = "{def_path}({adjustment}")] - span_lo: Span, - #[suggestion_part(code = "{successor_pos}")] - span_hi: Span, - def_path: String, - adjustment: &'a str, - successor_pos: &'a str, - }, - #[multipart_suggestion( - infer_source_kind_closure_return, - style = "verbose", - applicability = "has-placeholders" - )] - ClosureReturn { - #[suggestion_part(code = "{start_span_code}")] - start_span: Span, - start_span_code: String, - #[suggestion_part(code = " }}")] - end_span: Option<Span>, - }, -} - -impl<'a> SourceKindMultiSuggestion<'a> { - pub fn new_fully_qualified( - span: Span, - def_path: String, - adjustment: &'a str, - successor: (&'a str, BytePos), - ) -> Self { - Self::FullyQualified { - span_lo: span.shrink_to_lo(), - span_hi: span.shrink_to_hi().with_hi(successor.1), - def_path, - adjustment, - successor_pos: successor.0, - } - } - - pub fn new_closure_return( - ty_info: String, - data: &'a FnRetTy<'a>, - should_wrap_expr: Option<Span>, - ) -> Self { - let arrow = match data { - FnRetTy::DefaultReturn(_) => " -> ", - _ => "", - }; - let (start_span, start_span_code, end_span) = match should_wrap_expr { - Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)), - None => (data.span(), format!("{arrow}{ty_info}"), None), - }; - Self::ClosureReturn { start_span, start_span_code, end_span } - } -} - -pub enum RegionOriginNote<'a> { - Plain { - span: Span, - msg: DiagMessage, - }, - WithName { - span: Span, - msg: DiagMessage, - name: &'a str, - continues: bool, - }, - WithRequirement { - span: Span, - requirement: ObligationCauseAsDiagArg<'a>, - expected_found: Option<(DiagStyledString, DiagStyledString)>, - }, -} - -impl Subdiagnostic for RegionOriginNote<'_> { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - let mut label_or_note = |span, msg: DiagMessage| { - let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); - let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); - let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span); - if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { - diag.span_label(span, msg); - } else if span_is_primary && expanded_sub_count == 0 { - diag.note(msg); - } else { - diag.span_note(span, msg); - } - }; - match self { - RegionOriginNote::Plain { span, msg } => { - label_or_note(span, msg); - } - RegionOriginNote::WithName { span, msg, name, continues } => { - label_or_note(span, msg); - diag.arg("name", name); - diag.arg("continues", continues); - } - RegionOriginNote::WithRequirement { - span, - requirement, - expected_found: Some((expected, found)), - } => { - label_or_note(span, fluent::infer_subtype); - diag.arg("requirement", requirement); - - diag.note_expected_found(&"", expected, &"", found); - } - RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => { - // FIXME: this really should be handled at some earlier stage. Our - // handling of region checking when type errors are present is - // *terrible*. - label_or_note(span, fluent::infer_subtype_2); - diag.arg("requirement", requirement); - } - }; - } -} - -pub enum LifetimeMismatchLabels { - InRet { - param_span: Span, - ret_span: Span, - span: Span, - label_var1: Option<Ident>, - }, - Normal { - hir_equal: bool, - ty_sup: Span, - ty_sub: Span, - span: Span, - sup: Option<Ident>, - sub: Option<Ident>, - }, -} - -impl Subdiagnostic for LifetimeMismatchLabels { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - match self { - LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { - diag.span_label(param_span, fluent::infer_declared_different); - diag.span_label(ret_span, fluent::infer_nothing); - diag.span_label(span, fluent::infer_data_returned); - diag.arg("label_var1_exists", label_var1.is_some()); - diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); - } - LifetimeMismatchLabels::Normal { - hir_equal, - ty_sup, - ty_sub, - span, - sup: label_var1, - sub: label_var2, - } => { - if hir_equal { - diag.span_label(ty_sup, fluent::infer_declared_multiple); - diag.span_label(ty_sub, fluent::infer_nothing); - diag.span_label(span, fluent::infer_data_lifetime_flow); - } else { - diag.span_label(ty_sup, fluent::infer_types_declared_different); - diag.span_label(ty_sub, fluent::infer_nothing); - diag.span_label(span, fluent::infer_data_flows); - diag.arg("label_var1_exists", label_var1.is_some()); - diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); - diag.arg("label_var2_exists", label_var2.is_some()); - diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default()); - } - } - } - } -} - -pub struct AddLifetimeParamsSuggestion<'a> { - pub tcx: TyCtxt<'a>, - pub generic_param_scope: LocalDefId, - pub sub: Region<'a>, - pub ty_sup: &'a hir::Ty<'a>, - pub ty_sub: &'a hir::Ty<'a>, - pub add_note: bool, -} - -impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - let mut mk_suggestion = || { - let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) - else { - return false; - }; - - let node = self.tcx.hir_node_by_def_id(anon_reg.def_id); - let is_impl = matches!(&node, hir::Node::ImplItem(_)); - let (generics, parent_generics) = match node { - hir::Node::Item(&hir::Item { - kind: hir::ItemKind::Fn(_, ref generics, ..), - .. - }) - | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) - | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => ( - generics, - match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id)) - { - hir::Node::Item(hir::Item { - kind: hir::ItemKind::Trait(_, _, ref generics, ..), - .. - }) - | hir::Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }), - .. - }) => Some(generics), - _ => None, - }, - ), - _ => return false, - }; - - let suggestion_param_name = generics - .params - .iter() - .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) - .map(|p| p.name.ident().name) - .find(|i| *i != kw::UnderscoreLifetime); - let introduce_new = suggestion_param_name.is_none(); - - let mut default = "'a".to_string(); - if let Some(parent_generics) = parent_generics { - let used: FxHashSet<_> = parent_generics - .params - .iter() - .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) - .map(|p| p.name.ident().name) - .filter(|i| *i != kw::UnderscoreLifetime) - .map(|l| l.to_string()) - .collect(); - if let Some(lt) = - ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it)) - { - // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc - // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is - // likely to be an over-constraining lifetime requirement, so we always add a - // lifetime to the `fn`. - default = lt; - } - } - let suggestion_param_name = - suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default); - - struct ImplicitLifetimeFinder { - suggestions: Vec<(Span, String)>, - suggestion_param_name: String, - } - - impl<'v> Visitor<'v> for ImplicitLifetimeFinder { - fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { - let make_suggestion = |ident: Ident| { - if ident.name == kw::Empty && ident.span.is_empty() { - format!("{}, ", self.suggestion_param_name) - } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() { - format!("{} ", self.suggestion_param_name) - } else { - self.suggestion_param_name.clone() - } - }; - match ty.kind { - hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { - for segment in path.segments { - if let Some(args) = segment.args { - if args.args.iter().all(|arg| { - matches!( - arg, - hir::GenericArg::Lifetime(lifetime) - if lifetime.ident.name == kw::Empty - ) - }) { - self.suggestions.push(( - segment.ident.span.shrink_to_hi(), - format!( - "<{}>", - args.args - .iter() - .map(|_| self.suggestion_param_name.clone()) - .collect::<Vec<_>>() - .join(", ") - ), - )); - } else { - for arg in args.args { - if let hir::GenericArg::Lifetime(lifetime) = arg - && lifetime.is_anonymous() - { - self.suggestions.push(( - lifetime.ident.span, - make_suggestion(lifetime.ident), - )); - } - } - } - } - } - } - hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { - self.suggestions - .push((lifetime.ident.span, make_suggestion(lifetime.ident))); - } - _ => {} - } - walk_ty(self, ty); - } - } - let mut visitor = ImplicitLifetimeFinder { - suggestions: vec![], - suggestion_param_name: suggestion_param_name.clone(), - }; - if let Some(fn_decl) = node.fn_decl() - && let hir::FnRetTy::Return(ty) = fn_decl.output - { - visitor.visit_ty(ty); - } - if visitor.suggestions.is_empty() { - // Do not suggest constraining the `&self` param, but rather the return type. - // If that is wrong (because it is not sufficient), a follow up error will tell the - // user to fix it. This way we lower the chances of *over* constraining, but still - // get the cake of "correctly" contrained in two steps. - visitor.visit_ty(self.ty_sup); - } - visitor.visit_ty(self.ty_sub); - if visitor.suggestions.is_empty() { - return false; - } - if introduce_new { - let new_param_suggestion = if let Some(first) = - generics.params.iter().find(|p| !p.name.ident().span.is_empty()) - { - (first.span.shrink_to_lo(), format!("{suggestion_param_name}, ")) - } else { - (generics.span, format!("<{suggestion_param_name}>")) - }; - - visitor.suggestions.push(new_param_suggestion); - } - diag.multipart_suggestion_verbose( - fluent::infer_lifetime_param_suggestion, - visitor.suggestions, - Applicability::MaybeIncorrect, - ); - diag.arg("is_impl", is_impl); - diag.arg("is_reuse", !introduce_new); - - true - }; - if mk_suggestion() && self.add_note { - diag.note(fluent::infer_lifetime_param_suggestion_elided); - } - } -} - -#[derive(Diagnostic)] -#[diag(infer_lifetime_mismatch, code = E0623)] -pub struct LifetimeMismatch<'a> { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub labels: LifetimeMismatchLabels, - #[subdiagnostic] - pub suggestion: AddLifetimeParamsSuggestion<'a>, -} - -pub struct IntroducesStaticBecauseUnmetLifetimeReq { - pub unmet_requirements: MultiSpan, - pub binding_span: Span, -} - -impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - mut self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - self.unmet_requirements - .push_span_label(self.binding_span, fluent::infer_msl_introduces_static); - diag.span_note(self.unmet_requirements, fluent::infer_msl_unmet_req); - } -} - -// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that -#[derive(Subdiagnostic)] -pub enum DoesNotOutliveStaticFromImpl { - #[note(infer_does_not_outlive_static_from_impl)] - Spanned { - #[primary_span] - span: Span, - }, - #[note(infer_does_not_outlive_static_from_impl)] - Unspanned, -} - -#[derive(Subdiagnostic)] -pub enum ImplicitStaticLifetimeSubdiag { - #[note(infer_implicit_static_lifetime_note)] - Note { - #[primary_span] - span: Span, - }, - #[suggestion( - infer_implicit_static_lifetime_suggestion, - style = "verbose", - code = " + '_", - applicability = "maybe-incorrect" - )] - Sugg { - #[primary_span] - span: Span, - }, -} - -#[derive(Diagnostic)] -#[diag(infer_mismatched_static_lifetime)] -pub struct MismatchedStaticLifetime<'a> { - #[primary_span] - pub cause_span: Span, - #[subdiagnostic] - pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq, - #[subdiagnostic] - pub expl: Option<note_and_explain::RegionExplanation<'a>>, - #[subdiagnostic] - pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl, - #[subdiagnostic] - pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>, -} - -#[derive(Diagnostic)] -pub enum ExplicitLifetimeRequired<'a> { - #[diag(infer_explicit_lifetime_required_with_ident, code = E0621)] - WithIdent { - #[primary_span] - #[label] - span: Span, - simple_ident: Ident, - named: String, - #[suggestion( - infer_explicit_lifetime_required_sugg_with_ident, - code = "{new_ty}", - applicability = "unspecified" - )] - new_ty_span: Span, - #[skip_arg] - new_ty: Ty<'a>, - }, - #[diag(infer_explicit_lifetime_required_with_param_type, code = E0621)] - WithParamType { - #[primary_span] - #[label] - span: Span, - named: String, - #[suggestion( - infer_explicit_lifetime_required_sugg_with_param_type, - code = "{new_ty}", - applicability = "unspecified" - )] - new_ty_span: Span, - #[skip_arg] - new_ty: Ty<'a>, - }, -} - -pub enum TyOrSig<'tcx> { - Ty(Highlighted<'tcx, Ty<'tcx>>), - ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>), -} - -impl IntoDiagArg for TyOrSig<'_> { - fn into_diag_arg(self) -> rustc_errors::DiagArgValue { - match self { - TyOrSig::Ty(ty) => ty.into_diag_arg(), - TyOrSig::ClosureSig(sig) => sig.into_diag_arg(), - } - } -} - -#[derive(Subdiagnostic)] -pub enum ActualImplExplNotes<'tcx> { - #[note(infer_actual_impl_expl_expected_signature_two)] - ExpectedSignatureTwo { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - lifetime_2: usize, - }, - #[note(infer_actual_impl_expl_expected_signature_any)] - ExpectedSignatureAny { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_signature_some)] - ExpectedSignatureSome { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_signature_nothing)] - ExpectedSignatureNothing { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - }, - #[note(infer_actual_impl_expl_expected_passive_two)] - ExpectedPassiveTwo { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - lifetime_2: usize, - }, - #[note(infer_actual_impl_expl_expected_passive_any)] - ExpectedPassiveAny { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_passive_some)] - ExpectedPassiveSome { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_passive_nothing)] - ExpectedPassiveNothing { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - }, - #[note(infer_actual_impl_expl_expected_other_two)] - ExpectedOtherTwo { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - lifetime_2: usize, - }, - #[note(infer_actual_impl_expl_expected_other_any)] - ExpectedOtherAny { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_other_some)] - ExpectedOtherSome { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - }, - #[note(infer_actual_impl_expl_expected_other_nothing)] - ExpectedOtherNothing { - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - }, - #[note(infer_actual_impl_expl_but_actually_implements_trait)] - ButActuallyImplementsTrait { - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - has_lifetime: bool, - lifetime: usize, - }, - #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)] - ButActuallyImplementedForTy { - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - has_lifetime: bool, - lifetime: usize, - ty: String, - }, - #[note(infer_actual_impl_expl_but_actually_ty_implements)] - ButActuallyTyImplements { - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - has_lifetime: bool, - lifetime: usize, - ty: String, - }, -} - -pub enum ActualImplExpectedKind { - Signature, - Passive, - Other, -} - -pub enum ActualImplExpectedLifetimeKind { - Two, - Any, - Some, - Nothing, -} - -impl<'tcx> ActualImplExplNotes<'tcx> { - pub fn new_expected( - kind: ActualImplExpectedKind, - lt_kind: ActualImplExpectedLifetimeKind, - leading_ellipsis: bool, - ty_or_sig: TyOrSig<'tcx>, - trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, - lifetime_1: usize, - lifetime_2: usize, - ) -> Self { - match (kind, lt_kind) { - (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => { - Self::ExpectedSignatureTwo { - leading_ellipsis, - ty_or_sig, - trait_path, - lifetime_1, - lifetime_2, - } - } - (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => { - Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => { - Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => { - Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path } - } - (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => { - Self::ExpectedPassiveTwo { - leading_ellipsis, - ty_or_sig, - trait_path, - lifetime_1, - lifetime_2, - } - } - (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => { - Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => { - Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => { - Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path } - } - (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => { - Self::ExpectedOtherTwo { - leading_ellipsis, - ty_or_sig, - trait_path, - lifetime_1, - lifetime_2, - } - } - (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => { - Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => { - Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } - } - (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => { - Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path } - } - } - } -} - -#[derive(Diagnostic)] -#[diag(infer_trait_placeholder_mismatch)] -pub struct TraitPlaceholderMismatch<'tcx> { - #[primary_span] - pub span: Span, - #[label(infer_label_satisfy)] - pub satisfy_span: Option<Span>, - #[label(infer_label_where)] - pub where_span: Option<Span>, - #[label(infer_label_dup)] - pub dup_span: Option<Span>, - pub def_id: String, - pub trait_def_id: String, - - #[subdiagnostic] - pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>, -} - -pub struct ConsiderBorrowingParamHelp { - pub spans: Vec<Span>, -} - -impl Subdiagnostic for ConsiderBorrowingParamHelp { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { - let mut type_param_span: MultiSpan = self.spans.clone().into(); - for &span in &self.spans { - // Seems like we can't call f() here as Into<DiagMessage> is required - type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing); - } - let msg = f(diag, fluent::infer_tid_param_help.into()); - diag.span_help(type_param_span, msg); - } -} - -#[derive(Subdiagnostic)] -#[help(infer_tid_rel_help)] -pub struct RelationshipHelp; - -#[derive(Diagnostic)] -#[diag(infer_trait_impl_diff)] -pub struct TraitImplDiff { - #[primary_span] - #[label(infer_found)] - pub sp: Span, - #[label(infer_expected)] - pub trait_sp: Span, - #[note(infer_expected_found)] - pub note: (), - #[subdiagnostic] - pub param_help: ConsiderBorrowingParamHelp, - #[subdiagnostic] - // Seems like subdiagnostics are always pushed to the end, so this one - // also has to be a subdiagnostic to maintain order. - pub rel_help: Option<RelationshipHelp>, - pub expected: String, - pub found: String, -} - -pub struct DynTraitConstraintSuggestion { - pub span: Span, - pub ident: Ident, -} - -impl Subdiagnostic for DynTraitConstraintSuggestion { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { - let mut multi_span: MultiSpan = vec![self.span].into(); - multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label); - multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement); - let msg = f(diag, fluent::infer_dtcs_has_req_note.into()); - diag.span_note(multi_span, msg); - let msg = f(diag, fluent::infer_dtcs_suggestion.into()); - diag.span_suggestion_verbose( - self.span.shrink_to_hi(), - msg, - " + '_", - Applicability::MaybeIncorrect, - ); - } -} - -#[derive(Diagnostic)] -#[diag(infer_but_calling_introduces, code = E0772)] -pub struct ButCallingIntroduces { - #[label(infer_label1)] - pub param_ty_span: Span, - #[primary_span] - #[label(infer_label2)] - pub cause_span: Span, - - pub has_param_name: bool, - pub param_name: String, - pub has_lifetime: bool, - pub lifetime: String, - pub assoc_item: Symbol, - pub has_impl_path: bool, - pub impl_path: String, -} - -pub struct ReqIntroducedLocations { - pub span: MultiSpan, - pub spans: Vec<Span>, - pub fn_decl_span: Span, - pub cause_span: Span, - pub add_label: bool, -} - -impl Subdiagnostic for ReqIntroducedLocations { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - mut self, - diag: &mut Diag<'_, G>, - f: &F, - ) { - for sp in self.spans { - self.span.push_span_label(sp, fluent::infer_ril_introduced_here); - } - - if self.add_label { - self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by); - } - self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of); - let msg = f(diag, fluent::infer_ril_static_introduced_by.into()); - diag.span_note(self.span, msg); - } -} - -pub struct MoreTargeted { - pub ident: Symbol, -} - -impl Subdiagnostic for MoreTargeted { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - diag.code(E0772); - diag.primary_message(fluent::infer_more_targeted); - diag.arg("ident", self.ident); - } -} - -#[derive(Diagnostic)] -#[diag(infer_but_needs_to_satisfy, code = E0759)] -pub struct ButNeedsToSatisfy { - #[primary_span] - pub sp: Span, - #[label(infer_influencer)] - pub influencer_point: Span, - #[label(infer_used_here)] - pub spans: Vec<Span>, - #[label(infer_require)] - pub require_span_as_label: Option<Span>, - #[note(infer_require)] - pub require_span_as_note: Option<Span>, - #[note(infer_introduced_by_bound)] - pub bound: Option<Span>, - - #[subdiagnostic] - pub req_introduces_loc: Option<ReqIntroducedLocations>, - - pub has_param_name: bool, - pub param_name: String, - pub spans_empty: bool, - pub has_lifetime: bool, - pub lifetime: String, -} - -#[derive(Diagnostic)] -#[diag(infer_outlives_content, code = E0312)] -pub struct OutlivesContent<'a> { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub notes: Vec<note_and_explain::RegionExplanation<'a>>, -} - -#[derive(Diagnostic)] -#[diag(infer_outlives_bound, code = E0476)] -pub struct OutlivesBound<'a> { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub notes: Vec<note_and_explain::RegionExplanation<'a>>, -} - -#[derive(Diagnostic)] -#[diag(infer_fulfill_req_lifetime, code = E0477)] -pub struct FulfillReqLifetime<'a> { - #[primary_span] - pub span: Span, - pub ty: Ty<'a>, - #[subdiagnostic] - pub note: Option<note_and_explain::RegionExplanation<'a>>, -} - -#[derive(Diagnostic)] -#[diag(infer_lf_bound_not_satisfied, code = E0478)] -pub struct LfBoundNotSatisfied<'a> { - #[primary_span] - pub span: Span, - #[subdiagnostic] - pub notes: Vec<note_and_explain::RegionExplanation<'a>>, -} - -#[derive(Diagnostic)] -#[diag(infer_ref_longer_than_data, code = E0491)] -pub struct RefLongerThanData<'a> { - #[primary_span] - pub span: Span, - pub ty: Ty<'a>, - #[subdiagnostic] - pub notes: Vec<note_and_explain::RegionExplanation<'a>>, -} - -#[derive(Subdiagnostic)] -pub enum WhereClauseSuggestions { - #[suggestion( - infer_where_remove, - code = "", - applicability = "machine-applicable", - style = "verbose" - )] - Remove { - #[primary_span] - span: Span, - }, - #[suggestion( - infer_where_copy_predicates, - code = "{space}where {trait_predicates}", - applicability = "machine-applicable", - style = "verbose" - )] - CopyPredicates { - #[primary_span] - span: Span, - space: &'static str, - trait_predicates: String, - }, -} - -#[derive(Subdiagnostic)] -pub enum SuggestRemoveSemiOrReturnBinding { - #[multipart_suggestion(infer_srs_remove_and_box, applicability = "machine-applicable")] - RemoveAndBox { - #[suggestion_part(code = "Box::new(")] - first_lo: Span, - #[suggestion_part(code = ")")] - first_hi: Span, - #[suggestion_part(code = "Box::new(")] - second_lo: Span, - #[suggestion_part(code = ")")] - second_hi: Span, - #[suggestion_part(code = "")] - sp: Span, - }, - #[suggestion( - infer_srs_remove, - style = "short", - code = "", - applicability = "machine-applicable" - )] - Remove { - #[primary_span] - sp: Span, - }, - #[suggestion( - infer_srs_add, - style = "verbose", - code = "{code}", - applicability = "maybe-incorrect" - )] - Add { - #[primary_span] - sp: Span, - code: String, - ident: Ident, - }, - #[note(infer_srs_add_one)] - AddOne { - #[primary_span] - spans: MultiSpan, - }, -} - -#[derive(Subdiagnostic)] -pub enum ConsiderAddingAwait { - #[help(infer_await_both_futures)] - BothFuturesHelp, - #[multipart_suggestion(infer_await_both_futures, applicability = "maybe-incorrect")] - BothFuturesSugg { - #[suggestion_part(code = ".await")] - first: Span, - #[suggestion_part(code = ".await")] - second: Span, - }, - #[suggestion( - infer_await_future, - code = ".await", - style = "verbose", - applicability = "maybe-incorrect" - )] - FutureSugg { - #[primary_span] - span: Span, - }, - #[note(infer_await_note)] - FutureSuggNote { - #[primary_span] - span: Span, - }, - #[multipart_suggestion( - infer_await_future, - style = "verbose", - applicability = "maybe-incorrect" - )] - FutureSuggMultiple { - #[suggestion_part(code = ".await")] - spans: Vec<Span>, - }, -} - -#[derive(Diagnostic)] -pub enum PlaceholderRelationLfNotSatisfied { - #[diag(infer_lf_bound_not_satisfied)] - HasBoth { - #[primary_span] - span: Span, - #[note(infer_prlf_defined_with_sub)] - sub_span: Span, - #[note(infer_prlf_must_outlive_with_sup)] - sup_span: Span, - sub_symbol: Symbol, - sup_symbol: Symbol, - #[note(infer_prlf_known_limitation)] - note: (), - }, - #[diag(infer_lf_bound_not_satisfied)] - HasSub { - #[primary_span] - span: Span, - #[note(infer_prlf_defined_with_sub)] - sub_span: Span, - #[note(infer_prlf_must_outlive_without_sup)] - sup_span: Span, - sub_symbol: Symbol, - #[note(infer_prlf_known_limitation)] - note: (), - }, - #[diag(infer_lf_bound_not_satisfied)] - HasSup { - #[primary_span] - span: Span, - #[note(infer_prlf_defined_without_sub)] - sub_span: Span, - #[note(infer_prlf_must_outlive_with_sup)] - sup_span: Span, - sup_symbol: Symbol, - #[note(infer_prlf_known_limitation)] - note: (), - }, - #[diag(infer_lf_bound_not_satisfied)] - HasNone { - #[primary_span] - span: Span, - #[note(infer_prlf_defined_without_sub)] - sub_span: Span, - #[note(infer_prlf_must_outlive_without_sup)] - sup_span: Span, - #[note(infer_prlf_known_limitation)] - note: (), - }, - #[diag(infer_lf_bound_not_satisfied)] - OnlyPrimarySpan { - #[primary_span] - span: Span, - #[note(infer_prlf_known_limitation)] - note: (), - }, -} - -#[derive(Diagnostic)] -#[diag(infer_opaque_captures_lifetime, code = E0700)] -pub struct OpaqueCapturesLifetime<'tcx> { - #[primary_span] - pub span: Span, - #[label] - pub opaque_ty_span: Span, - pub opaque_ty: Ty<'tcx>, -} - -#[derive(Subdiagnostic)] -pub enum FunctionPointerSuggestion<'a> { - #[suggestion( - infer_fps_use_ref, - code = "&{fn_name}", - style = "verbose", - applicability = "maybe-incorrect" - )] - UseRef { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - }, - #[suggestion( - infer_fps_remove_ref, - code = "{fn_name}", - style = "verbose", - applicability = "maybe-incorrect" - )] - RemoveRef { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - }, - #[suggestion( - infer_fps_cast, - code = "&({fn_name} as {sig})", - style = "verbose", - applicability = "maybe-incorrect" - )] - CastRef { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - #[skip_arg] - sig: Binder<'a, FnSig<'a>>, - }, - #[suggestion( - infer_fps_cast, - code = "{fn_name} as {sig}", - style = "verbose", - applicability = "maybe-incorrect" - )] - Cast { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - #[skip_arg] - sig: Binder<'a, FnSig<'a>>, - }, - #[suggestion( - infer_fps_cast_both, - code = "{fn_name} as {found_sig}", - style = "hidden", - applicability = "maybe-incorrect" - )] - CastBoth { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - #[skip_arg] - found_sig: Binder<'a, FnSig<'a>>, - expected_sig: Binder<'a, FnSig<'a>>, - }, - #[suggestion( - infer_fps_cast_both, - code = "&({fn_name} as {found_sig})", - style = "hidden", - applicability = "maybe-incorrect" - )] - CastBothRef { - #[primary_span] - span: Span, - #[skip_arg] - fn_name: String, - #[skip_arg] - found_sig: Binder<'a, FnSig<'a>>, - expected_sig: Binder<'a, FnSig<'a>>, - }, -} - -#[derive(Subdiagnostic)] -#[note(infer_fps_items_are_distinct)] -pub struct FnItemsAreDistinct; - -#[derive(Subdiagnostic)] -#[note(infer_fn_uniq_types)] -pub struct FnUniqTypes; - -#[derive(Subdiagnostic)] -#[help(infer_fn_consider_casting)] -pub struct FnConsiderCasting { - pub casting: String, -} - -#[derive(Subdiagnostic)] -pub enum SuggestAccessingField<'a> { - #[suggestion( - infer_suggest_accessing_field, - code = "{snippet}.{name}", - applicability = "maybe-incorrect" - )] - Safe { - #[primary_span] - span: Span, - snippet: String, - name: Symbol, - ty: Ty<'a>, - }, - #[suggestion( - infer_suggest_accessing_field, - code = "unsafe {{ {snippet}.{name} }}", - applicability = "maybe-incorrect" - )] - Unsafe { - #[primary_span] - span: Span, - snippet: String, - name: Symbol, - ty: Ty<'a>, - }, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion(infer_stp_wrap_one, applicability = "maybe-incorrect")] -pub struct SuggestTuplePatternOne { - pub variant: String, - #[suggestion_part(code = "{variant}(")] - pub span_low: Span, - #[suggestion_part(code = ")")] - pub span_high: Span, -} - -pub struct SuggestTuplePatternMany { - pub path: String, - pub cause_span: Span, - pub compatible_variants: Vec<String>, -} - -impl Subdiagnostic for SuggestTuplePatternMany { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - f: &F, - ) { - diag.arg("path", self.path); - let message = f(diag, crate::fluent_generated::infer_stp_wrap_many.into()); - diag.multipart_suggestions( - message, - self.compatible_variants.into_iter().map(|variant| { - vec![ - (self.cause_span.shrink_to_lo(), format!("{variant}(")), - (self.cause_span.shrink_to_hi(), ")".to_string()), - ] - }), - rustc_errors::Applicability::MaybeIncorrect, - ); - } -} - -#[derive(Subdiagnostic)] -pub enum TypeErrorAdditionalDiags { - #[suggestion( - infer_meant_byte_literal, - code = "b'{code}'", - applicability = "machine-applicable" - )] - MeantByteLiteral { - #[primary_span] - span: Span, - code: String, - }, - #[suggestion( - infer_meant_char_literal, - code = "'{code}'", - applicability = "machine-applicable" - )] - MeantCharLiteral { - #[primary_span] - span: Span, - code: String, - }, - #[multipart_suggestion(infer_meant_str_literal, applicability = "machine-applicable")] - MeantStrLiteral { - #[suggestion_part(code = "\"")] - start: Span, - #[suggestion_part(code = "\"")] - end: Span, - }, - #[suggestion( - infer_consider_specifying_length, - code = "{length}", - applicability = "maybe-incorrect" - )] - ConsiderSpecifyingLength { - #[primary_span] - span: Span, - length: u64, - }, - #[note(infer_try_cannot_convert)] - TryCannotConvert { found: String, expected: String }, - #[suggestion(infer_tuple_trailing_comma, code = ",", applicability = "machine-applicable")] - TupleOnlyComma { - #[primary_span] - span: Span, - }, - #[multipart_suggestion(infer_tuple_trailing_comma, applicability = "machine-applicable")] - TupleAlsoParentheses { - #[suggestion_part(code = "(")] - span_low: Span, - #[suggestion_part(code = ",)")] - span_high: Span, - }, - #[suggestion( - infer_suggest_add_let_for_letchains, - style = "verbose", - applicability = "machine-applicable", - code = "let " - )] - AddLetForLetChains { - #[primary_span] - span: Span, - }, -} - -#[derive(Diagnostic)] -pub enum ObligationCauseFailureCode { - #[diag(infer_oc_method_compat, code = E0308)] - MethodCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_type_compat, code = E0308)] - TypeCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_const_compat, code = E0308)] - ConstCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_try_compat, code = E0308)] - TryCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_match_compat, code = E0308)] - MatchCompat { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_if_else_different, code = E0308)] - IfElseDifferent { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_no_else, code = E0317)] - NoElse { - #[primary_span] - span: Span, - }, - #[diag(infer_oc_no_diverge, code = E0308)] - NoDiverge { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_fn_main_correct_type, code = E0580)] - FnMainCorrectType { - #[primary_span] - span: Span, - }, - #[diag(infer_oc_fn_start_correct_type, code = E0308)] - FnStartCorrectType { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_fn_lang_correct_type, code = E0308)] - FnLangCorrectType { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - lang_item_name: Symbol, - }, - #[diag(infer_oc_intrinsic_correct_type, code = E0308)] - IntrinsicCorrectType { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_method_correct_type, code = E0308)] - MethodCorrectType { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_closure_selfref, code = E0644)] - ClosureSelfref { - #[primary_span] - span: Span, - }, - #[diag(infer_oc_cant_coerce, code = E0308)] - CantCoerce { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, - #[diag(infer_oc_generic, code = E0308)] - Generic { - #[primary_span] - span: Span, - #[subdiagnostic] - subdiags: Vec<TypeErrorAdditionalDiags>, - }, -} - -#[derive(Subdiagnostic)] -pub enum AddPreciseCapturing { - #[suggestion( - infer_precise_capturing_new, - style = "verbose", - code = " + use<{concatenated_bounds}>", - applicability = "machine-applicable" - )] - New { - #[primary_span] - span: Span, - new_lifetime: Symbol, - concatenated_bounds: String, - }, - #[suggestion( - infer_precise_capturing_existing, - style = "verbose", - code = "{pre}{new_lifetime}{post}", - applicability = "machine-applicable" - )] - Existing { - #[primary_span] - span: Span, - new_lifetime: Symbol, - pre: &'static str, - post: &'static str, - }, -} - -pub struct AddPreciseCapturingAndParams { - pub suggs: Vec<(Span, String)>, - pub new_lifetime: Symbol, - pub apit_spans: Vec<Span>, -} - -impl Subdiagnostic for AddPreciseCapturingAndParams { - fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( - self, - diag: &mut Diag<'_, G>, - _f: &F, - ) { - diag.arg("new_lifetime", self.new_lifetime); - diag.multipart_suggestion_verbose( - fluent::infer_precise_capturing_new_but_apit, - self.suggs, - Applicability::MaybeIncorrect, - ); - diag.span_note(self.apit_spans, fluent::infer_warn_removing_apit_params); - } -} diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c9073d8c23e..7fc4e36d752 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -11,7 +11,6 @@ pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; -use crate::error_reporting::infer::TypeErrCtxt; use crate::infer::relate::RelateResult; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; use free_regions::RegionRelations; @@ -24,7 +23,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::Rollback; use rustc_data_structures::unify as ut; -use rustc_errors::{Diag, ErrorGuaranteed}; +use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::extension; use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; @@ -65,8 +65,6 @@ pub mod relate; pub mod resolve; pub(crate) mod snapshot; pub mod type_variable; -// FIXME(error_reporting): Where should we put this? -pub mod need_type_info; #[must_use] #[derive(Debug)] @@ -698,36 +696,24 @@ impl<'tcx> InferCtxt<'tcx> { self.next_trait_solver } - /// Creates a `TypeErrCtxt` for emitting various inference errors. - /// During typeck, use `FnCtxt::err_ctxt` instead. - pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { - TypeErrCtxt { - infcx: self, - sub_relations: Default::default(), - typeck_results: None, - fallback_has_occurred: false, - normalize_fn_sig: Box::new(|fn_sig| fn_sig), - autoderef_steps: Box::new(|ty| { - debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck"); - vec![(ty, vec![])] - }), - } - } - pub fn freshen<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T { t.fold_with(&mut self.freshener()) } - /// Returns the origin of the type variable identified by `vid`, or `None` - /// if this is not a type variable. + /// Returns the origin of the type variable identified by `vid`. /// - /// No attempt is made to resolve `ty`. - pub fn type_var_origin(&self, ty: Ty<'tcx>) -> Option<TypeVariableOrigin> { - match *ty.kind() { - ty::Infer(ty::TyVar(vid)) => { - Some(self.inner.borrow_mut().type_variables().var_origin(vid)) - } - _ => None, + /// No attempt is made to resolve `vid` to its root variable. + pub fn type_var_origin(&self, vid: TyVid) -> TypeVariableOrigin { + self.inner.borrow_mut().type_variables().var_origin(vid) + } + + /// Returns the origin of the const variable identified by `vid` + // FIXME: We should store origins separately from the unification table + // so this doesn't need to be optional. + pub fn const_var_origin(&self, vid: ConstVid) -> Option<ConstVariableOrigin> { + match self.inner.borrow_mut().const_unification_table().probe_value(vid) { + ConstVariableValue::Known { .. } => None, + ConstVariableValue::Unknown { origin, .. } => Some(origin), } } @@ -1589,60 +1575,6 @@ impl<'tcx> InferCtxt<'tcx> { } } -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - // [Note-Type-error-reporting] - // An invariant is that anytime the expected or actual type is Error (the special - // error type, meaning that an error occurred when typechecking this expression), - // this is a derived error. The error cascaded from another error (that was already - // reported), so it's not useful to display it to the user. - // The following methods implement this logic. - // They check if either the actual or expected type is Error, and don't print the error - // in this case. The typechecker should only ever report type errors involving mismatched - // types using one of these methods, and should not call span_err directly for such - // errors. - pub fn type_error_struct_with_diag<M>( - &self, - sp: Span, - mk_diag: M, - actual_ty: Ty<'tcx>, - ) -> Diag<'a> - where - M: FnOnce(String) -> Diag<'a>, - { - let actual_ty = self.resolve_vars_if_possible(actual_ty); - debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); - - let mut err = mk_diag(self.ty_to_string(actual_ty)); - - // Don't report an error if actual type is `Error`. - if actual_ty.references_error() { - err.downgrade_to_delayed_bug(); - } - - err - } - - pub fn report_mismatched_types( - &self, - cause: &ObligationCause<'tcx>, - expected: Ty<'tcx>, - actual: Ty<'tcx>, - err: TypeError<'tcx>, - ) -> Diag<'a> { - self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err) - } - - pub fn report_mismatched_consts( - &self, - cause: &ObligationCause<'tcx>, - expected: ty::Const<'tcx>, - actual: ty::Const<'tcx>, - err: TypeError<'tcx>, - ) -> Diag<'a> { - self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) - } -} - /// Helper for [InferCtxt::ty_or_const_infer_var_changed] (see comment on that), currently /// used only for `traits::fulfill`'s list of `stalled_on` inference variables. #[derive(Copy, Clone, Debug)] @@ -1888,3 +1820,32 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>( args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 }) } + +impl<'tcx> InferCtxt<'tcx> { + /// Given a [`hir::Block`], get the span of its last expression or + /// statement, peeling off any inner blocks. + pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span { + let block = block.innermost_block(); + if let Some(expr) = &block.expr { + expr.span + } else if let Some(stmt) = block.stmts.last() { + // possibly incorrect trailing `;` in the else arm + stmt.span + } else { + // empty block; point at its entirety + block.span + } + } + + /// Given a [`hir::HirId`] for a block, get the span of its last expression + /// or statement, peeling off any inner blocks. + pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span { + match self.tcx.hir_node(hir_id) { + hir::Node::Block(blk) => self.find_block_span(blk), + // The parser was in a weird state if either of these happen, but + // it's better not to panic. + hir::Node::Expr(e) => e.span, + _ => rustc_span::DUMMY_SP, + } + } +} diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 02ebf933f53..b65ac859667 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -34,7 +34,6 @@ #[macro_use] extern crate tracing; -pub mod error_reporting; mod errors; pub mod infer; pub mod traits; diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs deleted file mode 100644 index 7730fe29e09..00000000000 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ /dev/null @@ -1,204 +0,0 @@ -use super::ObjectSafetyViolation; - -use crate::infer::InferCtxt; -use rustc_data_structures::fx::FxIndexSet; -use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag, MultiSpan}; -use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::Span; -use std::fmt; -use std::iter; - -impl<'tcx> InferCtxt<'tcx> { - pub fn report_extra_impl_obligation<'a>( - &'a self, - error_span: Span, - impl_item_def_id: LocalDefId, - trait_item_def_id: DefId, - requirement: &dyn fmt::Display, - ) -> Diag<'a> { - let mut err = struct_span_code_err!( - self.dcx(), - error_span, - E0276, - "impl has stricter requirements than trait" - ); - - if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) { - if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) { - let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); - err.span_label(span, format!("definition of `{item_name}` from trait")); - } - } - - err.span_label(error_span, format!("impl has extra requirement {requirement}")); - - err - } -} - -pub fn report_object_safety_error<'tcx>( - tcx: TyCtxt<'tcx>, - span: Span, - hir_id: Option<hir::HirId>, - trait_def_id: DefId, - violations: &[ObjectSafetyViolation], -) -> Diag<'tcx> { - let trait_str = tcx.def_path_str(trait_def_id); - let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { - 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", - 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, - ); - } - } - let mut reported_violations = FxIndexSet::default(); - let mut multi_span = vec![]; - let mut messages = vec![]; - for violation in violations { - if let ObjectSafetyViolation::SizedSelf(sp) = &violation - && !sp.is_empty() - { - // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations - // with a `Span`. - reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); - } - 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()) - } else { - format!("...because {}", violation.error_msg()) - }; - if spans.is_empty() { - err.note(msg); - } else { - for span in spans { - multi_span.push(span); - messages.push(msg.clone()); - } - } - } - } - 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..."); - } - for (span, msg) in iter::zip(multi_span, messages) { - note_span.push_span_label(span, msg); - } - err.span_note( - note_span, - "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \ - to be resolvable dynamically; for more information visit \ - <https://doc.rust-lang.org/reference/items/traits.html#object-safety>", - ); - - // 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(); - // Allows us to skip suggesting that the same item should be moved to another trait multiple times. - potential_solutions.dedup(); - for solution in potential_solutions { - solution.add_to(&mut err); - } - } - - 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() - // 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 - } 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 mut types = impls - .iter() - .map(|t| { - with_no_trimmed_paths!(format!(" {}", tcx.type_of(*t).instantiate_identity(),)) - }) - .collect::<Vec<_>>(); - types.sort(); - 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 externally_visible { - err.note(format!( - "`{trait_str}` 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", - )); - } - - err -} diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index 556b3bd063d..7bc3af374fc 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -3,7 +3,6 @@ //! [rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html mod engine; -pub mod error_reporting; mod project; mod structural_impls; pub mod util; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 290f91045c4..fc073233d97 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -322,6 +322,8 @@ fn register_builtins(store: &mut LintStore) { REFINING_IMPL_TRAIT_INTERNAL ); + add_lint_group!("deprecated_safe", DEPRECATED_SAFE_2024); + // Register renamed and removed lints. store.register_renamed("single_use_lifetime", "single_use_lifetimes"); store.register_renamed("elided_lifetime_in_path", "elided_lifetimes_in_paths"); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 04764b71b10..2f4e6a32308 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -37,7 +37,7 @@ declare_lint_pass! { DEPRECATED, DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME, DEPRECATED_IN_FUTURE, - DEPRECATED_SAFE, + DEPRECATED_SAFE_2024, DEPRECATED_WHERE_CLAUSE_LOCATION, DUPLICATE_MACRO_ATTRIBUTES, ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, @@ -4812,8 +4812,8 @@ declare_lint! { } declare_lint! { - /// The `deprecated_safe` lint detects unsafe functions being used as safe - /// functions. + /// The `deprecated_safe_2024` lint detects unsafe functions being used as + /// safe functions. /// /// ### Example /// @@ -4832,8 +4832,8 @@ declare_lint! { /// /// Rust [editions] allow the language to evolve without breaking backward /// compatibility. This lint catches code that uses `unsafe` functions that - /// were declared as safe (non-`unsafe`) in earlier editions. If you switch - /// the compiler to a new edition without updating the code, then it + /// were declared as safe (non-`unsafe`) in editions prior to Rust 2024. If + /// you switch the compiler to Rust 2024 without updating the code, then it /// will fail to compile if you are using a function previously marked as /// safe. /// @@ -4850,7 +4850,7 @@ declare_lint! { /// future. /// /// [editions]: https://doc.rust-lang.org/edition-guide/ - pub DEPRECATED_SAFE, + pub DEPRECATED_SAFE_2024, Allow, "detects unsafe functions being used as safe functions", @future_incompatible = FutureIncompatibleInfo { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 0ba9b940eed..e5e430bc90d 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -7,6 +7,7 @@ use crate::rmeta::*; use rustc_ast as ast; use rustc_data_structures::captures::Captures; use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::sync::{Lock, Lrc, OnceLock}; use rustc_data_structures::unhash::UnhashMap; @@ -83,12 +84,12 @@ pub(crate) struct CrateMetadata { /// Trait impl data. /// FIXME: Used only from queries and can use query cache, /// so pre-decoding can probably be avoided. - trait_impls: FxHashMap<(u32, DefIndex), LazyArray<(DefIndex, Option<SimplifiedType>)>>, + trait_impls: FxIndexMap<(u32, DefIndex), LazyArray<(DefIndex, Option<SimplifiedType>)>>, /// Inherent impls which do not follow the normal coherence rules. /// /// These can be introduced using either `#![rustc_coherence_is_core]` /// or `#[rustc_allow_incoherent_impl]`. - incoherent_impls: FxHashMap<SimplifiedType, LazyArray<DefIndex>>, + incoherent_impls: FxIndexMap<SimplifiedType, LazyArray<DefIndex>>, /// Proc macro descriptions for this crate, if it's a proc macro crate. raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 8596a0645e4..6f31c0fa520 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2,7 +2,7 @@ use crate::errors::{FailCreateFileEncoder, FailWriteFile}; use crate::rmeta::*; use rustc_ast::Attribute; -use rustc_data_structures::fx::FxIndexSet; +use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::sync::{join, par_for_each_in, Lrc}; use rustc_data_structures::temp_dir::MaybeTempDir; @@ -13,7 +13,6 @@ use rustc_hir_pretty::id_to_string; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::metadata_symbol_name; use rustc_middle::mir::interpret; -use rustc_middle::query::LocalCrate; use rustc_middle::query::Providers; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; @@ -1509,10 +1508,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - let inherent_impls = tcx.with_stable_hashing_context(|hcx| { - tcx.crate_inherent_impls(()).unwrap().inherent_impls.to_sorted(&hcx, true) - }); - for (def_id, impls) in inherent_impls { + for (def_id, impls) in &tcx.crate_inherent_impls(()).unwrap().inherent_impls { record_defaulted_array!(self.tables.inherent_impls[def_id.to_def_id()] <- impls.iter().map(|def_id| { assert!(def_id.is_local()); def_id.index @@ -2002,8 +1998,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_impls(&mut self) -> LazyArray<TraitImpls> { empty_proc_macro!(self); let tcx = self.tcx; - let mut fx_hash_map: FxHashMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>> = - FxHashMap::default(); + let mut trait_impls: FxIndexMap<DefId, Vec<(DefIndex, Option<SimplifiedType>)>> = + FxIndexMap::default(); for id in tcx.hir().items() { let DefKind::Impl { of_trait } = tcx.def_kind(id.owner_id) else { @@ -2022,7 +2018,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { trait_ref.self_ty(), TreatParams::AsCandidateKey, ); - fx_hash_map + trait_impls .entry(trait_ref.def_id) .or_default() .push((id.owner_id.def_id.local_def_index, simplified_self_ty)); @@ -2043,47 +2039,30 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } - let mut all_impls: Vec<_> = fx_hash_map.into_iter().collect(); - - // Bring everything into deterministic order for hashing - all_impls.sort_by_cached_key(|&(trait_def_id, _)| tcx.def_path_hash(trait_def_id)); - - let all_impls: Vec<_> = all_impls + let trait_impls: Vec<_> = trait_impls .into_iter() - .map(|(trait_def_id, mut impls)| { - // Bring everything into deterministic order for hashing - impls.sort_by_cached_key(|&(index, _)| { - tcx.hir().def_path_hash(LocalDefId { local_def_index: index }) - }); - - TraitImpls { - trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index), - impls: self.lazy_array(&impls), - } + .map(|(trait_def_id, impls)| TraitImpls { + trait_id: (trait_def_id.krate.as_u32(), trait_def_id.index), + impls: self.lazy_array(&impls), }) .collect(); - self.lazy_array(&all_impls) + self.lazy_array(&trait_impls) } #[instrument(level = "debug", skip(self))] fn encode_incoherent_impls(&mut self) -> LazyArray<IncoherentImpls> { empty_proc_macro!(self); let tcx = self.tcx; - let all_impls = tcx.with_stable_hashing_context(|hcx| { - tcx.crate_inherent_impls(()).unwrap().incoherent_impls.to_sorted(&hcx, true) - }); - let all_impls: Vec<_> = all_impls - .into_iter() - .map(|(&simp, impls)| { - let mut impls: Vec<_> = - impls.into_iter().map(|def_id| def_id.local_def_index).collect(); - impls.sort_by_cached_key(|&local_def_index| { - tcx.hir().def_path_hash(LocalDefId { local_def_index }) - }); - - IncoherentImpls { self_ty: simp, impls: self.lazy_array(impls) } + let all_impls: Vec<_> = tcx + .crate_inherent_impls(()) + .unwrap() + .incoherent_impls + .iter() + .map(|(&simp, impls)| IncoherentImpls { + self_ty: simp, + impls: self.lazy_array(impls.iter().map(|def_id| def_id.local_def_index)), }) .collect(); @@ -2327,32 +2306,6 @@ pub fn provide(providers: &mut Providers) { span_bug!(tcx.def_span(def_id), "no traits in scope for a doc link") }) }, - traits: |tcx, LocalCrate| { - let mut traits = Vec::new(); - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) { - traits.push(id.owner_id.to_def_id()) - } - } - - // Bring everything into deterministic order. - traits.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); - tcx.arena.alloc_slice(&traits) - }, - trait_impls_in_crate: |tcx, LocalCrate| { - let mut trait_impls = Vec::new(); - for id in tcx.hir().items() { - if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) - && tcx.impl_trait_ref(id.owner_id).is_some() - { - trait_impls.push(id.owner_id.to_def_id()) - } - } - - // Bring everything into deterministic order. - trait_impls.sort_by_cached_key(|&def_id| tcx.def_path_hash(def_id)); - tcx.arena.alloc_slice(&trait_impls) - }, ..*providers } diff --git a/compiler/rustc_middle/src/hooks/mod.rs b/compiler/rustc_middle/src/hooks/mod.rs index bf10a71dbae..75dc685a16a 100644 --- a/compiler/rustc_middle/src/hooks/mod.rs +++ b/compiler/rustc_middle/src/hooks/mod.rs @@ -103,6 +103,10 @@ declare_hooks! { /// Create a list-like THIR representation for debugging. hook thir_flat(key: LocalDefId) -> String; + + /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we + /// can just link to the upstream crate and therefore don't need a mono item. + hook should_codegen_locally(instance: crate::ty::Instance<'tcx>) -> bool; } #[cold] diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index bdd1eb11a38..15febfa7d9c 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -12,15 +12,13 @@ use std::fmt; use std::io; use std::io::{Read, Write}; use std::num::NonZero; -use std::sync::atomic::{AtomicU32, Ordering}; -use smallvec::{smallvec, SmallVec}; use tracing::{debug, trace}; use rustc_ast::LitKind; use rustc_attr::InlineAttr; use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::sync::{HashMapExt, Lock}; +use rustc_data_structures::sync::Lock; use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; @@ -159,14 +157,9 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>( } } -// Used to avoid infinite recursion when decoding cyclic allocations. -type DecodingSessionId = NonZero<u32>; - #[derive(Clone)] enum State { Empty, - InProgressNonAlloc(SmallVec<[DecodingSessionId; 1]>), - InProgress(SmallVec<[DecodingSessionId; 1]>, AllocId), Done(AllocId), } @@ -180,13 +173,7 @@ pub struct AllocDecodingState { impl AllocDecodingState { #[inline] pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> { - static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0); - let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst); - - // Make sure this is never zero. - let session_id = DecodingSessionId::new((counter & 0x7FFFFFFF) + 1).unwrap(); - - AllocDecodingSession { state: self, session_id } + AllocDecodingSession { state: self } } pub fn new(data_offsets: Vec<u64>) -> Self { @@ -200,7 +187,6 @@ impl AllocDecodingState { #[derive(Copy, Clone)] pub struct AllocDecodingSession<'s> { state: &'s AllocDecodingState, - session_id: DecodingSessionId, } impl<'s> AllocDecodingSession<'s> { @@ -220,70 +206,35 @@ impl<'s> AllocDecodingSession<'s> { (alloc_kind, decoder.position()) }); + // We are going to hold this lock during the entire decoding of this allocation, which may + // require that we decode other allocations. This cannot deadlock for two reasons: + // + // At the time of writing, it is only possible to create an allocation that contains a pointer + // to itself using the const_allocate intrinsic (which is for testing only), and even attempting + // to evaluate such consts blows the stack. If we ever grow a mechanism for producing + // cyclic allocations, we will need a new strategy for decoding that doesn't bring back + // https://github.com/rust-lang/rust/issues/126741. + // + // It is also impossible to create two allocations (call them A and B) where A is a pointer to B, and B + // is a pointer to A, because attempting to evaluate either of those consts will produce a + // query cycle, failing compilation. + let mut entry = self.state.decoding_state[idx].lock(); // Check the decoding state to see if it's already decoded or if we should // decode it here. - let alloc_id = { - let mut entry = self.state.decoding_state[idx].lock(); - - match *entry { - State::Done(alloc_id) => { - return alloc_id; - } - ref mut entry @ State::Empty => { - // We are allowed to decode. - match alloc_kind { - AllocDiscriminant::Alloc => { - // If this is an allocation, we need to reserve an - // `AllocId` so we can decode cyclic graphs. - let alloc_id = decoder.interner().reserve_alloc_id(); - *entry = State::InProgress(smallvec![self.session_id], alloc_id); - Some(alloc_id) - } - AllocDiscriminant::Fn - | AllocDiscriminant::Static - | AllocDiscriminant::VTable => { - // Fns and statics cannot be cyclic, and their `AllocId` - // is determined later by interning. - *entry = State::InProgressNonAlloc(smallvec![self.session_id]); - None - } - } - } - State::InProgressNonAlloc(ref mut sessions) => { - if sessions.contains(&self.session_id) { - bug!("this should be unreachable"); - } else { - // Start decoding concurrently. - sessions.push(self.session_id); - None - } - } - State::InProgress(ref mut sessions, alloc_id) => { - if sessions.contains(&self.session_id) { - // Don't recurse. - return alloc_id; - } else { - // Start decoding concurrently. - sessions.push(self.session_id); - Some(alloc_id) - } - } - } - }; + if let State::Done(alloc_id) = *entry { + return alloc_id; + } // Now decode the actual data. let alloc_id = decoder.with_position(pos, |decoder| { match alloc_kind { AllocDiscriminant::Alloc => { + trace!("creating memory alloc ID"); let alloc = <ConstAllocation<'tcx> as Decodable<_>>::decode(decoder); - // We already have a reserved `AllocId`. - let alloc_id = alloc_id.unwrap(); - trace!("decoded alloc {:?}: {:#?}", alloc_id, alloc); - decoder.interner().set_alloc_id_same_memory(alloc_id, alloc); - alloc_id + trace!("decoded alloc {:?}", alloc); + decoder.interner().reserve_and_set_memory_alloc(alloc) } AllocDiscriminant::Fn => { - assert!(alloc_id.is_none()); trace!("creating fn alloc ID"); let instance = ty::Instance::decode(decoder); trace!("decoded fn alloc instance: {:?}", instance); @@ -291,35 +242,26 @@ impl<'s> AllocDecodingSession<'s> { // Here we cannot call `reserve_and_set_fn_alloc` as that would use a query, which // is not possible in this context. That's why the allocation stores // whether it is unique or not. - let alloc_id = - decoder.interner().reserve_and_set_fn_alloc_internal(instance, unique); - alloc_id + decoder.interner().reserve_and_set_fn_alloc_internal(instance, unique) } AllocDiscriminant::VTable => { - assert!(alloc_id.is_none()); trace!("creating vtable alloc ID"); let ty = <Ty<'_> as Decodable<D>>::decode(decoder); let poly_trait_ref = <Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder); trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}"); - let alloc_id = - decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref); - alloc_id + decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref) } AllocDiscriminant::Static => { - assert!(alloc_id.is_none()); trace!("creating extern static alloc ID"); let did = <DefId as Decodable<D>>::decode(decoder); trace!("decoded static def-ID: {:?}", did); - let alloc_id = decoder.interner().reserve_and_set_static_alloc(did); - alloc_id + decoder.interner().reserve_and_set_static_alloc(did) } } }); - self.state.decoding_state[idx].with_lock(|entry| { - *entry = State::Done(alloc_id); - }); + *entry = State::Done(alloc_id); alloc_id } @@ -563,12 +505,6 @@ impl<'tcx> TyCtxt<'tcx> { bug!("tried to set allocation ID {id:?}, but it was already existing as {old:#?}"); } } - - /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called - /// twice for the same `(AllocId, Allocation)` pair. - fn set_alloc_id_same_memory(self, id: AllocId, mem: ConstAllocation<'tcx>) { - self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem)); - } } //////////////////////////////////////////////////////////////////////////////// diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index bd073cd891f..558590af7ec 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -40,7 +40,6 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::tagged_ptr::CopyTaggedPtr; -use rustc_data_structures::unord::UnordMap; use rustc_errors::{Diag, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; @@ -2083,6 +2082,8 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { trait_impls_of: trait_def::trait_impls_of_provider, incoherent_impls: trait_def::incoherent_impls_provider, + trait_impls_in_crate: trait_def::trait_impls_in_crate_provider, + traits: trait_def::traits_provider, const_param_default: consts::const_param_default, vtable_allocation: vtable::vtable_allocation_provider, ..*providers @@ -2096,8 +2097,8 @@ pub fn provide(providers: &mut Providers) { /// (constructing this map requires touching the entire crate). #[derive(Clone, Debug, Default, HashStable)] pub struct CrateInherentImpls { - pub inherent_impls: LocalDefIdMap<Vec<DefId>>, - pub incoherent_impls: UnordMap<SimplifiedType, Vec<LocalDefId>>, + pub inherent_impls: FxIndexMap<LocalDefId, Vec<DefId>>, + pub incoherent_impls: FxIndexMap<SimplifiedType, Vec<LocalDefId>>, } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, HashStable)] diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index da5860043c9..3bd9f6ad11b 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -1,16 +1,19 @@ -use crate::traits::specialization_graph; -use crate::ty::fast_reject::{self, SimplifiedType, TreatParams}; -use crate::ty::{Ident, Ty, TyCtxt}; -use hir::def_id::LOCAL_CRATE; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; use std::iter; use tracing::debug; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_macros::{Decodable, Encodable, HashStable}; +use crate::query::LocalCrate; +use crate::traits::specialization_graph; +use crate::ty::fast_reject::{self, SimplifiedType, TreatParams}; +use crate::ty::{Ident, Ty, TyCtxt}; + /// A trait's definition with type information. #[derive(HashStable, Encodable, Decodable)] pub struct TraitDef { @@ -274,3 +277,27 @@ pub(super) fn incoherent_impls_provider( Ok(tcx.arena.alloc_slice(&impls)) } + +pub(super) fn traits_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] { + let mut traits = Vec::new(); + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) { + traits.push(id.owner_id.to_def_id()) + } + } + + tcx.arena.alloc_slice(&traits) +} + +pub(super) fn trait_impls_in_crate_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> &[DefId] { + let mut trait_impls = Vec::new(); + for id in tcx.hir().items() { + if matches!(tcx.def_kind(id.owner_id), DefKind::Impl { .. }) + && tcx.impl_trait_ref(id.owner_id).is_some() + { + trait_impls.push(id.owner_id.to_def_id()) + } + } + + tcx.arena.alloc_slice(&trait_impls) +} diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 7f4a2e73d33..95bc8b3d0cb 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -1598,6 +1598,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { for subcandidate in candidate.subcandidates.iter_mut() { expanded_candidates.push(subcandidate); } + // Note that the subcandidates have been added to `expanded_candidates`, + // but `candidate` itself has not. If the last candidate has more match pairs, + // they are handled separately by `test_remaining_match_pairs_after_or`. } else { // A candidate that doesn't start with an or-pattern has nothing to // expand, so it is included in the post-expansion list as-is. @@ -1613,19 +1616,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expanded_candidates.as_mut_slice(), ); - // Simplify subcandidates and process any leftover match pairs. - for candidate in candidates_to_expand { + // Postprocess subcandidates, and process any leftover match pairs. + // (Only the last candidate can possibly have more match pairs.) + debug_assert!({ + let mut all_except_last = candidates_to_expand.iter().rev().skip(1); + all_except_last.all(|candidate| candidate.match_pairs.is_empty()) + }); + for candidate in candidates_to_expand.iter_mut() { if !candidate.subcandidates.is_empty() { - self.finalize_or_candidate(span, scrutinee_span, candidate); + self.merge_trivial_subcandidates(candidate); + self.remove_never_subcandidates(candidate); } } + if let Some(last_candidate) = candidates_to_expand.last_mut() { + self.test_remaining_match_pairs_after_or(span, scrutinee_span, last_candidate); + } remainder_start.and(remaining_candidates) } /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new - /// subcandidate. Any candidate that has been expanded that way should be passed to - /// `finalize_or_candidate` after its subcandidates have been processed. + /// subcandidate. Any candidate that has been expanded this way should also be postprocessed + /// at the end of [`Self::expand_and_match_or_candidates`]. fn create_or_subcandidates<'pat>( &mut self, candidate: &mut Candidate<'pat, 'tcx>, @@ -1642,7 +1654,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block; } - /// Simplify subcandidates and process any leftover match pairs. The candidate should have been + /// Try to merge all of the subcandidates of the given candidate into one. This avoids + /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been /// expanded with `create_or_subcandidates`. /// /// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like @@ -1695,103 +1708,128 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// | /// ... /// ``` - fn finalize_or_candidate( - &mut self, - span: Span, - scrutinee_span: Span, - candidate: &mut Candidate<'_, 'tcx>, - ) { - if candidate.subcandidates.is_empty() { + /// + /// Note that this takes place _after_ the subcandidates have participated + /// in match tree lowering. + fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { + assert!(!candidate.subcandidates.is_empty()); + if candidate.has_guard { + // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard. return; } - self.merge_trivial_subcandidates(candidate); + // FIXME(or_patterns; matthewjasper) Try to be more aggressive here. + let can_merge = candidate.subcandidates.iter().all(|subcandidate| { + subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty() + }); + if !can_merge { + return; + } - if !candidate.match_pairs.is_empty() { - let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span); - let source_info = self.source_info(or_span); - // If more match pairs remain, test them after each subcandidate. - // We could add them to the or-candidates before the call to `test_or_pattern` but this - // would make it impossible to detect simplifiable or-patterns. That would guarantee - // exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`. - let mut last_otherwise = None; - candidate.visit_leaves(|leaf_candidate| { - last_otherwise = leaf_candidate.otherwise_block; - }); - let remaining_match_pairs = mem::take(&mut candidate.match_pairs); - candidate.visit_leaves(|leaf_candidate| { - assert!(leaf_candidate.match_pairs.is_empty()); - leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned()); - let or_start = leaf_candidate.pre_binding_block.unwrap(); - let otherwise = - self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]); - // In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q, - // R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching - // directly to `last_otherwise`. If there is a guard, - // `leaf_candidate.otherwise_block` can be reached by guard failure as well, so we - // can't skip `Q`. - let or_otherwise = if leaf_candidate.has_guard { - leaf_candidate.otherwise_block.unwrap() - } else { - last_otherwise.unwrap() - }; - self.cfg.goto(otherwise, source_info, or_otherwise); - }); + let mut last_otherwise = None; + let shared_pre_binding_block = self.cfg.start_new_block(); + // This candidate is about to become a leaf, so unset `or_span`. + let or_span = candidate.or_span.take().unwrap(); + let source_info = self.source_info(or_span); + + if candidate.false_edge_start_block.is_none() { + candidate.false_edge_start_block = candidate.subcandidates[0].false_edge_start_block; + } + + // Remove the (known-trivial) subcandidates from the candidate tree, + // so that they aren't visible after match tree lowering, and wire them + // all to join up at a single shared pre-binding block. + // (Note that the subcandidates have already had their part of the match + // tree lowered by this point, which is why we can add a goto to them.) + for subcandidate in mem::take(&mut candidate.subcandidates) { + let subcandidate_block = subcandidate.pre_binding_block.unwrap(); + self.cfg.goto(subcandidate_block, source_info, shared_pre_binding_block); + last_otherwise = subcandidate.otherwise_block; } + candidate.pre_binding_block = Some(shared_pre_binding_block); + assert!(last_otherwise.is_some()); + candidate.otherwise_block = last_otherwise; } - /// Try to merge all of the subcandidates of the given candidate into one. This avoids - /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been - /// expanded with `create_or_subcandidates`. - fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { - if candidate.subcandidates.is_empty() || candidate.has_guard { - // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard. + /// Never subcandidates may have a set of bindings inconsistent with their siblings, + /// which would break later code. So we filter them out. Note that we can't filter out + /// top-level candidates this way. + fn remove_never_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) { + if candidate.subcandidates.is_empty() { return; } - // FIXME(or_patterns; matthewjasper) Try to be more aggressive here. - let can_merge = candidate.subcandidates.iter().all(|subcandidate| { - subcandidate.subcandidates.is_empty() && subcandidate.extra_data.is_empty() - }); - if can_merge { - let mut last_otherwise = None; - let any_matches = self.cfg.start_new_block(); - let or_span = candidate.or_span.take().unwrap(); - let source_info = self.source_info(or_span); - if candidate.false_edge_start_block.is_none() { - candidate.false_edge_start_block = - candidate.subcandidates[0].false_edge_start_block; - } - for subcandidate in mem::take(&mut candidate.subcandidates) { - let or_block = subcandidate.pre_binding_block.unwrap(); - self.cfg.goto(or_block, source_info, any_matches); - last_otherwise = subcandidate.otherwise_block; - } - candidate.pre_binding_block = Some(any_matches); - assert!(last_otherwise.is_some()); - candidate.otherwise_block = last_otherwise; - } else { - // Never subcandidates may have a set of bindings inconsistent with their siblings, - // which would break later code. So we filter them out. Note that we can't filter out - // top-level candidates this way. - candidate.subcandidates.retain_mut(|candidate| { - if candidate.extra_data.is_never { - candidate.visit_leaves(|subcandidate| { - let block = subcandidate.pre_binding_block.unwrap(); - // That block is already unreachable but needs a terminator to make the MIR well-formed. - let source_info = self.source_info(subcandidate.extra_data.span); - self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); - }); - false - } else { - true - } - }); - if candidate.subcandidates.is_empty() { - // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`. - candidate.pre_binding_block = Some(self.cfg.start_new_block()); + candidate.subcandidates.retain_mut(|candidate| { + if candidate.extra_data.is_never { + candidate.visit_leaves(|subcandidate| { + let block = subcandidate.pre_binding_block.unwrap(); + // That block is already unreachable but needs a terminator to make the MIR well-formed. + let source_info = self.source_info(subcandidate.extra_data.span); + self.cfg.terminate(block, source_info, TerminatorKind::Unreachable); + }); + false + } else { + true } + }); + if candidate.subcandidates.is_empty() { + // If `candidate` has become a leaf candidate, ensure it has a `pre_binding_block`. + candidate.pre_binding_block = Some(self.cfg.start_new_block()); + } + } + + /// If more match pairs remain, test them after each subcandidate. + /// We could have added them to the or-candidates during or-pattern expansion, but that + /// would make it impossible to detect simplifiable or-patterns. That would guarantee + /// exponentially large CFGs for cases like `(1 | 2, 3 | 4, ...)`. + fn test_remaining_match_pairs_after_or( + &mut self, + span: Span, + scrutinee_span: Span, + candidate: &mut Candidate<'_, 'tcx>, + ) { + if candidate.match_pairs.is_empty() { + return; } + + let or_span = candidate.or_span.unwrap_or(candidate.extra_data.span); + let source_info = self.source_info(or_span); + let mut last_otherwise = None; + candidate.visit_leaves(|leaf_candidate| { + last_otherwise = leaf_candidate.otherwise_block; + }); + + let remaining_match_pairs = mem::take(&mut candidate.match_pairs); + // We're testing match pairs that remained after an `Or`, so the remaining + // pairs should all be `Or` too, due to the sorting invariant. + debug_assert!( + remaining_match_pairs + .iter() + .all(|match_pair| matches!(match_pair.test_case, TestCase::Or { .. })) + ); + + candidate.visit_leaves(|leaf_candidate| { + // At this point the leaf's own match pairs have all been lowered + // and removed, so `extend` and assignment are equivalent, + // but extending can also recycle any existing vector capacity. + assert!(leaf_candidate.match_pairs.is_empty()); + leaf_candidate.match_pairs.extend(remaining_match_pairs.iter().cloned()); + + let or_start = leaf_candidate.pre_binding_block.unwrap(); + let otherwise = + self.match_candidates(span, scrutinee_span, or_start, &mut [leaf_candidate]); + // In a case like `(P | Q, R | S)`, if `P` succeeds and `R | S` fails, we know `(Q, + // R | S)` will fail too. If there is no guard, we skip testing of `Q` by branching + // directly to `last_otherwise`. If there is a guard, + // `leaf_candidate.otherwise_block` can be reached by guard failure as well, so we + // can't skip `Q`. + let or_otherwise = if leaf_candidate.has_guard { + leaf_candidate.otherwise_block.unwrap() + } else { + last_otherwise.unwrap() + }; + self.cfg.goto(otherwise, source_info, or_otherwise); + }); } /// Pick a test to run. Which test doesn't matter as long as it is guaranteed to fully match at diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index a65586ccdb7..bff4d6af4aa 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -10,7 +10,7 @@ use rustc_middle::thir::visit::Visitor; use rustc_middle::thir::*; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; -use rustc_session::lint::builtin::{DEPRECATED_SAFE, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; +use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::Symbol; @@ -99,7 +99,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { { let sm = self.tcx.sess.source_map(); self.tcx.emit_node_span_lint( - DEPRECATED_SAFE, + DEPRECATED_SAFE_2024, self.hir_context, span, CallToDeprecatedSafeFnRequiresUnsafe { 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 70065b5a2c3..95799cec94b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -16,8 +16,8 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_pattern_analysis::errors::Uncovered; use rustc_pattern_analysis::rustc::{ - Constructor, DeconstructedPat, MatchArm, RustcPatCtxt as PatCtxt, Usefulness, UsefulnessReport, - WitnessPat, + Constructor, DeconstructedPat, MatchArm, RevealedTy, RustcPatCtxt as PatCtxt, Usefulness, + UsefulnessReport, WitnessPat, }; use rustc_session::lint::builtin::{ BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS, @@ -998,27 +998,31 @@ fn report_non_exhaustive_match<'p, 'tcx>( err.note(format!("the matched value is of type `{}`", scrut_ty)); if !is_empty_match { - let mut non_exhaustive_tys = FxIndexSet::default(); + let mut special_tys = FxIndexSet::default(); // Look at the first witness. - collect_non_exhaustive_tys(cx, &witnesses[0], &mut non_exhaustive_tys); + collect_special_tys(cx, &witnesses[0], &mut special_tys); - for ty in non_exhaustive_tys { + for ty in special_tys { if ty.is_ptr_sized_integral() { - if ty == cx.tcx.types.usize { + if ty.inner() == cx.tcx.types.usize { err.note(format!( "`{ty}` does not have a fixed maximum value, so half-open ranges are necessary to match \ exhaustively", )); - } else if ty == cx.tcx.types.isize { + } else if ty.inner() == cx.tcx.types.isize { err.note(format!( "`{ty}` does not have fixed minimum and maximum values, so half-open ranges are necessary to match \ exhaustively", )); } - } else if ty == cx.tcx.types.str_ { + } else if ty.inner() == cx.tcx.types.str_ { err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary"); - } else if cx.is_foreign_non_exhaustive_enum(cx.reveal_opaque_ty(ty)) { + } else if cx.is_foreign_non_exhaustive_enum(ty) { err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively")); + } else if cx.is_uninhabited(ty.inner()) && cx.tcx.features().min_exhaustive_patterns { + // The type is uninhabited yet there is a witness: we must be in the `MaybeInvalid` + // case. + err.note(format!("`{ty}` is uninhabited but is not being matched by value, so a wildcard `_` is required")); } } } @@ -1168,22 +1172,22 @@ fn joined_uncovered_patterns<'p, 'tcx>( } } -fn collect_non_exhaustive_tys<'tcx>( +/// Collect types that require specific explanations when they show up in witnesses. +fn collect_special_tys<'tcx>( cx: &PatCtxt<'_, 'tcx>, pat: &WitnessPat<'_, 'tcx>, - non_exhaustive_tys: &mut FxIndexSet<Ty<'tcx>>, + special_tys: &mut FxIndexSet<RevealedTy<'tcx>>, ) { - if matches!(pat.ctor(), Constructor::NonExhaustive) { - non_exhaustive_tys.insert(pat.ty().inner()); + if matches!(pat.ctor(), Constructor::NonExhaustive | Constructor::Never) { + special_tys.insert(*pat.ty()); } if let Constructor::IntRange(range) = pat.ctor() { if cx.is_range_beyond_boundaries(range, *pat.ty()) { // The range denotes the values before `isize::MIN` or the values after `usize::MAX`/`isize::MAX`. - non_exhaustive_tys.insert(pat.ty().inner()); + special_tys.insert(*pat.ty()); } } - pat.iter_fields() - .for_each(|field_pat| collect_non_exhaustive_tys(cx, field_pat, non_exhaustive_tys)) + pat.iter_fields().for_each(|field_pat| collect_special_tys(cx, field_pat, special_tys)) } fn report_adt_defined_here<'tcx>( diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 261dcd52d71..658cc4c51a9 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -81,7 +81,7 @@ use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{FieldIdx, VariantIdx}; use rustc_target::spec::PanicStrategy; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt as _; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::TyCtxtInferExt as _; use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index bfd505c0672..3655a677ba0 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -228,6 +228,7 @@ use rustc_middle::ty::{ self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, VtblEntry, }; +use rustc_middle::util::Providers; use rustc_middle::{bug, span_bug}; use rustc_session::config::EntryFnType; use rustc_session::Limit; @@ -399,7 +400,7 @@ fn collect_items_rec<'tcx>( let instance = Instance::mono(tcx, def_id); // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, instance)); + debug_assert!(tcx.should_codegen_locally(instance)); let DefKind::Static { nested, .. } = tcx.def_kind(def_id) else { bug!() }; // Nested statics have no type. @@ -431,7 +432,7 @@ fn collect_items_rec<'tcx>( } MonoItem::Fn(instance) => { // Sanity check whether this ended up being collected accidentally - debug_assert!(should_codegen_locally(tcx, instance)); + debug_assert!(tcx.should_codegen_locally(instance)); // Keep track of the monomorphization recursion depth recursion_depth_reset = Some(check_recursion_limit( @@ -475,7 +476,7 @@ fn collect_items_rec<'tcx>( } hir::InlineAsmOperand::SymStatic { path: _, def_id } => { let instance = Instance::mono(tcx, *def_id); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { trace!("collecting static {:?}", def_id); used_items.push(dummy_spanned(MonoItem::Static(*def_id))); } @@ -712,7 +713,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { if let ty::Closure(def_id, args) = *source_ty.kind() { let instance = Instance::resolve_closure(self.tcx, def_id, args, ty::ClosureKind::FnOnce); - if should_codegen_locally(self.tcx, instance) { + if self.tcx.should_codegen_locally(instance) { self.used_items.push(create_fn_mono_item(self.tcx, instance, span)); } } else { @@ -722,7 +723,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { mir::Rvalue::ThreadLocalRef(def_id) => { assert!(self.tcx.is_thread_local_static(def_id)); let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, instance) { + if self.tcx.should_codegen_locally(instance) { trace!("collecting thread-local static {:?}", def_id); self.used_items.push(respan(span, MonoItem::Static(def_id))); } @@ -749,7 +750,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { let tcx = self.tcx; let push_mono_lang_item = |this: &mut Self, lang_item: LangItem| { let instance = Instance::mono(tcx, tcx.require_lang_item(lang_item, Some(source))); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { this.used_items.push(create_fn_mono_item(tcx, instance, source)); } }; @@ -783,7 +784,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> { } mir::InlineAsmOperand::SymStatic { def_id } => { let instance = Instance::mono(self.tcx, def_id); - if should_codegen_locally(self.tcx, instance) { + if self.tcx.should_codegen_locally(instance) { trace!("collecting asm sym static {:?}", def_id); self.used_items.push(respan(source, MonoItem::Static(def_id))); } @@ -873,7 +874,7 @@ fn visit_instance_use<'tcx>( output: &mut MonoItems<'tcx>, ) { debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call); - if !should_codegen_locally(tcx, instance) { + if !tcx.should_codegen_locally(instance) { return; } if let ty::InstanceKind::Intrinsic(def_id) = instance.def { @@ -885,13 +886,13 @@ fn visit_instance_use<'tcx>( // codegen a call to that function without generating code for the function itself. let def_id = tcx.require_lang_item(LangItem::PanicNounwind, None); let panic_instance = Instance::mono(tcx, def_id); - if should_codegen_locally(tcx, panic_instance) { + if tcx.should_codegen_locally(panic_instance) { output.push(create_fn_mono_item(tcx, panic_instance, source)); } } else if tcx.has_attr(def_id, sym::rustc_intrinsic) { // Codegen the fallback body of intrinsics with fallback bodies let instance = ty::Instance::new(def_id, instance.args); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { output.push(create_fn_mono_item(tcx, instance, source)); } } @@ -930,7 +931,7 @@ fn visit_instance_use<'tcx>( /// Returns `true` if we should codegen an instance in the local crate, or returns `false` if we /// can just link to the upstream crate and therefore don't need a mono item. -pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> bool { +fn should_codegen_locally<'tcx>(tcx: TyCtxtAt<'tcx>, instance: Instance<'tcx>) -> bool { let Some(def_id) = instance.def.def_id_if_not_guaranteed_local_codegen() else { return true; }; @@ -946,7 +947,7 @@ pub(crate) fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance } if tcx.is_reachable_non_generic(def_id) - || instance.polymorphize(tcx).upstream_monomorphization(tcx).is_some() + || instance.polymorphize(*tcx).upstream_monomorphization(*tcx).is_some() { // We can link to the item in question, no instance needed in this crate. return false; @@ -1127,7 +1128,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( None } VtblEntry::Method(instance) => { - Some(*instance).filter(|instance| should_codegen_locally(tcx, *instance)) + Some(*instance).filter(|instance| tcx.should_codegen_locally(*instance)) } }) .map(|item| create_fn_mono_item(tcx, item, source)); @@ -1144,7 +1145,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt GlobalAlloc::Static(def_id) => { assert!(!tcx.is_thread_local_static(def_id)); let instance = Instance::mono(tcx, def_id); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { trace!("collecting static {:?}", def_id); output.push(dummy_spanned(MonoItem::Static(def_id))); } @@ -1162,7 +1163,7 @@ fn collect_alloc<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIt } } GlobalAlloc::Function { instance, .. } => { - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { trace!("collecting {:?} with {:#?}", alloc_id, instance); output.push(create_fn_mono_item(tcx, instance, DUMMY_SP)); } @@ -1284,7 +1285,7 @@ fn visit_mentioned_item<'tcx>( if let ty::Closure(def_id, args) = *source_ty.kind() { let instance = Instance::resolve_closure(tcx, def_id, args, ty::ClosureKind::FnOnce); - if should_codegen_locally(tcx, instance) { + if tcx.should_codegen_locally(instance) { output.push(create_fn_mono_item(tcx, instance, span)); } } else { @@ -1557,7 +1558,7 @@ fn create_mono_items_for_default_impls<'tcx>( let instance = ty::Instance::expect_resolve(tcx, param_env, method.def_id, args, DUMMY_SP); let mono_item = create_fn_mono_item(tcx, instance, DUMMY_SP); - if mono_item.node.is_instantiable(tcx) && should_codegen_locally(tcx, instance) { + if mono_item.node.is_instantiable(tcx) && tcx.should_codegen_locally(instance) { output.push(mono_item); } } @@ -1613,3 +1614,7 @@ pub(crate) fn collect_crate_mono_items<'tcx>( (mono_items, state.usage_map.into_inner()) } + +pub fn provide(providers: &mut Providers) { + providers.hooks.should_codegen_locally = should_codegen_locally; +} diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index aa3b4cd5b67..fc6e8e0d14f 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -5,14 +5,11 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::bug; -use rustc_middle::query::{Providers, TyCtxtAt}; +use rustc_middle::query::TyCtxtAt; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; -use rustc_middle::ty::Instance; -use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{self, Ty}; -use rustc_span::def_id::DefId; -use rustc_span::def_id::LOCAL_CRATE; +use rustc_middle::util::Providers; use rustc_span::ErrorGuaranteed; mod collector; @@ -21,8 +18,6 @@ mod partitioning; mod polymorphize; mod util; -use collector::should_codegen_locally; - rustc_fluent_macro::fluent_messages! { "../messages.ftl" } fn custom_coerce_unsize_info<'tcx>( @@ -47,34 +42,6 @@ fn custom_coerce_unsize_info<'tcx>( } } -/// Returns whether a call from the current crate to the [`Instance`] would produce a call -/// from `compiler_builtins` to a symbol the linker must resolve. -/// -/// Such calls from `compiler_bultins` are effectively impossible for the linker to handle. Some -/// linkers will optimize such that dead calls to unresolved symbols are not an error, but this is -/// not guaranteed. So we used this function in codegen backends to ensure we do not generate any -/// unlinkable calls. -/// -/// Note that calls to LLVM intrinsics are uniquely okay because they won't make it to the linker. -pub fn is_call_from_compiler_builtins_to_upstream_monomorphization<'tcx>( - tcx: TyCtxt<'tcx>, - instance: Instance<'tcx>, -) -> bool { - fn is_llvm_intrinsic(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - if let Some(name) = tcx.codegen_fn_attrs(def_id).link_name { - name.as_str().starts_with("llvm.") - } else { - false - } - } - - let def_id = instance.def_id(); - !def_id.is_local() - && tcx.is_compiler_builtins(LOCAL_CRATE) - && !is_llvm_intrinsic(tcx, def_id) - && !should_codegen_locally(tcx, instance) -} - pub fn provide(providers: &mut Providers) { partitioning::provide(providers); polymorphize::provide(providers); diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 9a7c488833a..8c7c5e0074a 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -112,9 +112,9 @@ use rustc_middle::mir::mono::{ CodegenUnit, CodegenUnitNameBuilder, InstantiationMode, Linkage, MonoItem, MonoItemData, Visibility, }; -use rustc_middle::query::Providers; use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceKind, TyCtxt}; +use rustc_middle::util::Providers; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_session::CodegenUnits; use rustc_span::symbol::Symbol; @@ -1314,4 +1314,6 @@ pub fn provide(providers: &mut Providers) { .find(|cgu| cgu.name() == name) .unwrap_or_else(|| panic!("failed to find cgu with name {name:?}")) }; + + collector::provide(providers); } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ce2fa83810f..9cbd989cc0e 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -34,7 +34,7 @@ use rustc_session::parse::feature_err; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs}; use rustc_trait_selection::traits::ObligationCtxt; use std::cell::Cell; diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 603e98cfa92..6f59c782e06 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -8,7 +8,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, TargetDataLayout}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::{infer::TyCtxtInferExt, traits}; use crate::errors::{ diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index d17ee8bff50..6ef2d69273e 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -40,9 +40,15 @@ pub type WitnessPat<'p, 'tcx> = crate::pat::WitnessPat<RustcPatCtxt<'p, 'tcx>>; /// /// Use `.inner()` or deref to get to the `Ty<'tcx>`. #[repr(transparent)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct RevealedTy<'tcx>(Ty<'tcx>); +impl<'tcx> fmt::Display for RevealedTy<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(fmt) + } +} + impl<'tcx> fmt::Debug for RevealedTy<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(fmt) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dc7200465d9..51414d78596 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -2763,7 +2763,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let res = match kind { RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()), RibKind::Normal => { - if self.r.tcx.features().non_lifetime_binders { + // FIXME(non_lifetime_binders): Stop special-casing + // const params to error out here. + if self.r.tcx.features().non_lifetime_binders + && matches!(param.kind, GenericParamKind::Type { .. }) + { Res::Def(def_kind, def_id.to_def_id()) } else { Res::Err diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b64efadb261..2b30ca8a894 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -177,6 +177,7 @@ symbols! { CoerceUnsized, Command, ConstParamTy, + ConstParamTy_, Context, Continue, Copy, @@ -336,6 +337,7 @@ symbols! { TyKind, Unknown, Unsize, + UnsizedConstParamTy, Upvars, Vec, VecDeque, @@ -1689,6 +1691,7 @@ symbols! { rvalue_static_promotion, rwpi, s, + s390x_target_feature, safety, sanitize, sanitizer_cfi_generalize_pointers, @@ -2001,6 +2004,8 @@ symbols! { unsafe_no_drop_flag, unsafe_pin_internals, unsize, + unsized_const_param_ty, + unsized_const_params, unsized_fn_params, unsized_locals, unsized_tuple_coercion, diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 6667efb14e2..4fb0323b6cf 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -4,6 +4,9 @@ use rustc_span::symbol::Symbol; /// Features that control behaviour of rustc, rather than the codegen. pub const RUSTC_SPECIFIC_FEATURES: &[&str] = &["crt-static"]; +/// Features that require special handling when passing to LLVM. +pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"]; + /// Stability information for target features. #[derive(Debug, Clone, Copy)] pub enum Stability { @@ -397,6 +400,13 @@ const LOONGARCH_ALLOWED_FEATURES: &[(&str, Stability)] = &[ // tidy-alphabetical-end ]; +const IBMZ_ALLOWED_FEATURES: &[(&str, Stability)] = &[ + // tidy-alphabetical-start + ("backchain", Unstable(sym::s390x_target_feature)), + ("vector", Unstable(sym::s390x_target_feature)), + // tidy-alphabetical-end +]; + /// When rustdoc is running, provide a list of all known features so that all their respective /// primitives may be documented. /// @@ -414,6 +424,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Stability)> { .chain(BPF_ALLOWED_FEATURES.iter()) .chain(CSKY_ALLOWED_FEATURES) .chain(LOONGARCH_ALLOWED_FEATURES) + .chain(IBMZ_ALLOWED_FEATURES) .cloned() } @@ -431,6 +442,7 @@ impl super::spec::Target { "bpf" => BPF_ALLOWED_FEATURES, "csky" => CSKY_ALLOWED_FEATURES, "loongarch64" => LOONGARCH_ALLOWED_FEATURES, + "s390x" => IBMZ_ALLOWED_FEATURES, _ => &[], } } diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl index f96bd985237..137850f31d3 100644 --- a/compiler/rustc_trait_selection/messages.ftl +++ b/compiler/rustc_trait_selection/messages.ftl @@ -1,3 +1,65 @@ +trait_selection_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} +} +trait_selection_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} +} +trait_selection_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime -> + [true] , for some specific lifetime `'{$lifetime}` + *[false] {""} +} + +trait_selection_actual_impl_expl_expected_other_any = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_other_nothing = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}` + +trait_selection_actual_impl_expl_expected_other_some = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_other_two = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +trait_selection_actual_impl_expl_expected_passive_any = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}` +trait_selection_actual_impl_expl_expected_passive_some = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_passive_two = {$leading_ellipsis -> + [true] ... + *[false] {""} +}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... +trait_selection_actual_impl_expl_expected_signature_any = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}` +trait_selection_actual_impl_expl_expected_signature_some = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`... +trait_selection_actual_impl_expl_expected_signature_two = {$leading_ellipsis -> + [true] ... + *[false] {""} +}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`... trait_selection_adjust_signature_borrow = consider adjusting the signature so it borrows its {$len -> [one] argument *[other] arguments @@ -8,8 +70,48 @@ trait_selection_adjust_signature_remove_borrow = consider adjusting the signatur *[other] arguments } +trait_selection_ascribe_user_type_prove_predicate = ...so that the where clause holds + trait_selection_async_closure_not_fn = async closure does not implement `{$kind}` because it captures state from its environment +trait_selection_await_both_futures = consider `await`ing on both `Future`s +trait_selection_await_future = consider `await`ing on the `Future` +trait_selection_await_note = calling an async function returns a future + +trait_selection_but_calling_introduces = {$has_param_name -> + [true] `{$param_name}` + *[false] `fn` parameter +} has {$lifetime_kind -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` +} but calling `{$assoc_item}` introduces an implicit `'static` lifetime requirement + .label1 = {$has_lifetime -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` + } + .label2 = ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the {$has_impl_path -> + [true] `impl` of `{$impl_path}` + *[false] inherent `impl` + } + +trait_selection_but_needs_to_satisfy = {$has_param_name -> + [true] `{$param_name}` + *[false] `fn` parameter +} has {$has_lifetime -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` +} but it needs to satisfy a `'static` lifetime requirement + .influencer = this data with {$has_lifetime -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` + }... + .require = {$spans_empty -> + *[true] ...is used and required to live as long as `'static` here + [false] ...and is required to live as long as `'static` here + } + .used_here = ...is used here... + .introduced_by_bound = `'static` lifetime requirement introduced by this bound + trait_selection_closure_fn_mut_label = closure is `{$trait_prefix}FnMut` because it mutates the variable `{$place}` here trait_selection_closure_fn_once_label = closure is `{$trait_prefix}FnOnce` because it moves the variable `{$place}` out of its environment @@ -19,18 +121,67 @@ trait_selection_closure_kind_mismatch = expected a closure that implements the ` trait_selection_closure_kind_requirement = the requirement to implement `{$trait_prefix}{$expected}` derives from here +trait_selection_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait +trait_selection_consider_specifying_length = consider specifying the actual array length +trait_selection_data_flows = ...but data{$label_var1_exists -> + [true] {" "}from `{$label_var1}` + *[false] {""} +} flows{$label_var2_exists -> + [true] {" "}into `{$label_var2}` + *[false] {""} +} here + +trait_selection_data_lifetime_flow = ...but data with one lifetime flows into the other here +trait_selection_data_returned = ...but data{$label_var1_exists -> + [true] {" "}from `{$label_var1}` + *[false] {""} +} is returned here + +trait_selection_declared_different = this parameter and the return type are declared with different lifetimes... +trait_selection_declared_multiple = this type is declared with multiple lifetimes... trait_selection_disallowed_positional_argument = positional format arguments are not allowed here .help = only named format arguments with the name of one of the generic types are allowed in this context +trait_selection_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl` +trait_selection_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement +trait_selection_dtcs_has_req_note = the used `impl` has a `'static` requirement +trait_selection_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement +trait_selection_dtcs_suggestion = consider relaxing the implicit `'static` requirement + trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries} trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]` .label = empty on-clause here +trait_selection_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}` + +trait_selection_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type + +trait_selection_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}` + .label = lifetime `{$named}` required + +trait_selection_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type + .label = lifetime `{$named}` required + +trait_selection_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}` + +trait_selection_fn_uniq_types = different fn items have unique types, even if their signatures are the same +trait_selection_fps_cast = consider casting to a fn pointer +trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}` + +trait_selection_fps_items_are_distinct = fn items are distinct from fn pointers +trait_selection_fps_remove_ref = consider removing the reference +trait_selection_fps_use_ref = consider using a reference +trait_selection_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime + +trait_selection_full_type_written = the full type name has been written to '{$path}' + trait_selection_ignored_diagnostic_option = `{$option_name}` is ignored due to previous definition of `{$option_name}` .other_label = `{$option_name}` is first declared here .label = `{$option_name}` is already declared here +trait_selection_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement +trait_selection_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}` trait_selection_invalid_format_specifier = invalid format specifier @@ -39,13 +190,52 @@ trait_selection_invalid_format_specifier = invalid format specifier trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]` .label = invalid on-clause here +trait_selection_label_bad = {$bad_kind -> + *[other] cannot infer type + [more_info] cannot infer {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] the value of const parameter + [const] the value of the constant + } `{$name}`{$has_parent -> + [true] {" "}declared on the {$parent_prefix} `{$parent_name}` + *[false] {""} + } +} + +trait_selection_lf_bound_not_satisfied = lifetime bound not satisfied +trait_selection_lifetime_mismatch = lifetime mismatch + +trait_selection_lifetime_param_suggestion = consider {$is_reuse -> + [true] reusing + *[false] introducing +} a named lifetime parameter{$is_impl -> + [true] {" "}and update trait if needed + *[false] {""} +} +trait_selection_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime + trait_selection_malformed_on_unimplemented_attr = malformed `on_unimplemented` attribute .help = only `message`, `note` and `label` are allowed as options .label = invalid option found here +trait_selection_meant_byte_literal = if you meant to write a byte literal, prefix with `b` +trait_selection_meant_char_literal = if you meant to write a `char` literal, use single quotes +trait_selection_meant_str_literal = if you meant to write a string literal, use double quotes +trait_selection_mismatched_static_lifetime = incompatible lifetime on type trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute .help = at least one of the `message`, `note` and `label` options are expected +trait_selection_more_targeted = {$has_param_name -> + [true] `{$param_name}` + *[false] `fn` parameter +} has {$has_lifetime -> + [true] lifetime `{$lifetime}` + *[false] an anonymous lifetime `'_` +} but calling `{$ident}` introduces an implicit `'static` lifetime requirement + +trait_selection_msl_introduces_static = introduces a `'static` lifetime requirement +trait_selection_msl_unmet_req = because this has an unmet lifetime requirement + trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc -> [none] {""} *[default] {" "}for type `{$self_desc}` @@ -59,13 +249,214 @@ trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a .label = expected value here .note = eg `#[rustc_on_unimplemented(message="foo")]` +trait_selection_nothing = {""} + +trait_selection_oc_cant_coerce = cannot coerce intrinsics to function pointers +trait_selection_oc_closure_selfref = closure/coroutine type that references itself +trait_selection_oc_const_compat = const not compatible with trait +trait_selection_oc_fn_lang_correct_type = {$lang_item_name -> + [panic_impl] `#[panic_handler]` + *[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 +trait_selection_oc_intrinsic_correct_type = intrinsic has wrong type +trait_selection_oc_match_compat = `match` arms have incompatible types +trait_selection_oc_method_compat = method not compatible with trait +trait_selection_oc_method_correct_type = mismatched `self` parameter type +trait_selection_oc_no_diverge = `else` clause of `let...else` does not diverge +trait_selection_oc_no_else = `if` may be missing an `else` clause +trait_selection_oc_try_compat = `?` operator has incompatible types +trait_selection_oc_type_compat = type not compatible with trait +trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds + .label = opaque type defined here + +trait_selection_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type +trait_selection_outlives_content = lifetime of reference outlives lifetime of borrowed content... + +trait_selection_precise_capturing_existing = add `{$new_lifetime}` to the `use<...>` bound to explicitly capture it +trait_selection_precise_capturing_new = add a `use<...>` bound to explicitly capture `{$new_lifetime}` + +trait_selection_precise_capturing_new_but_apit = add a `use<...>` bound to explicitly capture `{$new_lifetime}` after turning all argument-position `impl Trait` into type parameters, noting that this possibly affects the API of this crate + +trait_selection_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here... +trait_selection_prlf_defined_without_sub = the lifetime defined here... +trait_selection_prlf_known_limitation = this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information) + +trait_selection_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here +trait_selection_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here +trait_selection_reborrow = ...so that reference does not outlive borrowed content +trait_selection_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references + +trait_selection_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at +trait_selection_region_explanation = {$pref_kind -> + *[should_not_happen] [{$pref_kind}] + [ref_valid_for] ...the reference is valid for + [content_valid_for] ...but the borrowed content is only valid for + [type_obj_valid_for] object type is valid for + [source_pointer_valid_for] source pointer is only valid for + [type_satisfy] type must satisfy + [type_outlive] type must outlive + [lf_param_instantiated_with] lifetime parameter instantiated with + [lf_param_must_outlive] but lifetime parameter must outlive + [lf_instantiated_with] lifetime instantiated with + [lf_must_outlive] but lifetime must outlive + [pointer_valid_for] the pointer is valid for + [data_valid_for] but the referenced data is only valid for + [empty] {""} +}{$pref_kind -> + [empty] {""} + *[other] {" "} +}{$desc_kind -> + *[should_not_happen] [{$desc_kind}] + [restatic] the static lifetime + [revar] lifetime {$desc_arg} + [as_defined] the lifetime `{$desc_arg}` as defined here + [as_defined_anon] the anonymous lifetime as defined here + [defined_here] the anonymous lifetime defined here + [defined_here_reg] the lifetime `{$desc_arg}` as defined here +}{$suff_kind -> + *[should_not_happen] [{$suff_kind}] + [empty]{""} + [continues] ... + [req_by_binding] {" "}as required by this binding +} + +trait_selection_relate_object_bound = ...so that it can be closed over into an object +trait_selection_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues -> + [true] ... + *[false] {""} +} +trait_selection_relate_param_bound_2 = ...that is required by this bound +trait_selection_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied +trait_selection_ril_because_of = because of this returned expression +trait_selection_ril_introduced_by = requirement introduced by this return type +trait_selection_ril_introduced_here = `'static` requirement introduced here +trait_selection_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type + +trait_selection_source_kind_closure_return = + try giving this closure an explicit return type + +# coroutine_kind may need to be translated +trait_selection_source_kind_fully_qualified = + try using a fully qualified path to specify the expected types + +trait_selection_source_kind_subdiag_generic_label = + cannot infer {$is_type -> + [true] type + *[false] the value + } of the {$is_type -> + [true] type + *[false] const + } {$parent_exists -> + [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}` + *[false] parameter {$param_name} + } + +trait_selection_source_kind_subdiag_generic_suggestion = + consider specifying the generic {$arg_count -> + [one] argument + *[other] arguments + } + +trait_selection_source_kind_subdiag_let = {$kind -> + [with_pattern] consider giving `{$name}` an explicit type + [closure] consider giving this closure parameter an explicit type + *[other] consider giving this pattern a type +}{$x_kind -> + [has_name] , where the {$prefix_kind -> + *[type] type for {$prefix} + [const_with_param] value of const parameter + [const] value of the constant + } `{$arg_name}` is specified + [underscore] , where the placeholders `_` are specified + *[empty] {""} +} + +trait_selection_srs_add = consider returning the local binding `{$ident}` +trait_selection_srs_add_one = consider returning one of these bindings + +trait_selection_srs_remove = consider removing this semicolon +trait_selection_srs_remove_and_box = consider removing this semicolon and boxing the expressions +trait_selection_stp_wrap_many = try wrapping the pattern in a variant of `{$path}` + +trait_selection_stp_wrap_one = try wrapping the pattern in `{$variant}` +trait_selection_subtype = ...so that the {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [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 + *[other] types are compatible +} +trait_selection_subtype_2 = ...so that {$requirement -> + [method_compat] method type is compatible with trait + [type_compat] associated type is compatible with trait + [const_compat] const is compatible with trait + [expr_assignable] expression is assignable + [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 + *[other] types are compatible +} + +trait_selection_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}` + +trait_selection_suggest_add_let_for_letchains = consider adding `let` + +trait_selection_tid_consider_borrowing = consider borrowing this type parameter in the trait +trait_selection_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` + +trait_selection_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output trait_selection_trait_has_no_impls = this trait has no implementations, consider adding one +trait_selection_trait_impl_diff = `impl` item signature doesn't match `trait` item signature + .found = found `{$found}` + .expected = expected `{$expected}` + .expected_found = expected signature `{$expected}` + {" "}found signature `{$found}` + +trait_selection_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough + .label_satisfy = doesn't satisfy where-clause + .label_where = due to a where-clause on `{$def_id}`... + .label_dup = implementation of `{$trait_def_id}` is not general enough + +trait_selection_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}` + +trait_selection_tuple_trailing_comma = use a trailing comma to create a tuple with one element + trait_selection_ty_alias_overflow = in case this is a recursive type alias, consider using a struct, enum, or union instead +trait_selection_type_annotations_needed = {$source_kind -> + [closure] type annotations needed for the closure `{$source_name}` + [normal] type annotations needed for `{$source_name}` + *[other] type annotations needed +} + .label = type must be known at this point + +trait_selection_types_declared_different = these two types are declared with different lifetimes... + trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated} trait_selection_unknown_format_parameter_for_on_unimplemented_attr = there is no parameter `{$argument_name}` on trait `{$trait_name}` .help = expect either a generic argument name or {"`{Self}`"} as format argument +trait_selection_warn_removing_apit_params = you could use a `use<...>` bound to explicitly capture `{$new_lifetime}`, but argument-position `impl Trait`s are not nameable + +trait_selection_where_copy_predicates = copy the `where` clause predicates from the trait + +trait_selection_where_remove = remove the `where` clause trait_selection_wrapped_parser_error = {$description} .label = {$label} diff --git a/compiler/rustc_infer/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index 9998fbca056..daabdec8f9e 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -46,14 +46,12 @@ //! time of error detection. use std::borrow::Cow; -use std::ops::{ControlFlow, Deref}; +use std::ops::ControlFlow; use std::path::PathBuf; use std::{cmp, fmt, iter}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_errors::{ - pluralize, Applicability, Diag, DiagCtxtHandle, DiagStyledString, IntoDiagArg, StringPart, -}; +use rustc_errors::{pluralize, Applicability, Diag, DiagStyledString, IntoDiagArg, StringPart}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; @@ -72,23 +70,23 @@ use rustc_middle::ty::{ use rustc_span::{sym, BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ObligationCauseFailureCode, TypeErrorAdditionalDiags}; use crate::infer; use crate::infer::relate::{self, RelateResult, TypeRelation}; use crate::infer::{InferCtxt, TypeTrace, ValuePairs}; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, - PredicateObligation, }; mod note_and_explain; mod suggest; +pub mod need_type_info; +pub mod nice_region_error; pub mod region; pub mod sub_relations; -pub mod nice_region_error; - /// Makes a valid string literal from a string by escaping special characters (" and \), /// unless they are already escaped. fn escape_literal(s: &str) -> String { @@ -111,48 +109,59 @@ fn escape_literal(s: &str) -> String { escaped } -/// A helper for building type related errors. The `typeck_results` -/// field is only populated during an in-progress typeck. -/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`. -/// -/// You must only create this if you intend to actually emit an error (or -/// perhaps a warning, though preferably not.) It provides a lot of utility -/// methods which should not be used during the happy path. -pub struct TypeErrCtxt<'a, 'tcx> { - pub infcx: &'a InferCtxt<'tcx>, - pub sub_relations: std::cell::RefCell<sub_relations::SubRelations>, - - pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>, - pub fallback_has_occurred: bool, +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + // [Note-Type-error-reporting] + // An invariant is that anytime the expected or actual type is Error (the special + // error type, meaning that an error occurred when typechecking this expression), + // this is a derived error. The error cascaded from another error (that was already + // reported), so it's not useful to display it to the user. + // The following methods implement this logic. + // They check if either the actual or expected type is Error, and don't print the error + // in this case. The typechecker should only ever report type errors involving mismatched + // types using one of these methods, and should not call span_err directly for such + // errors. + pub fn type_error_struct_with_diag<M>( + &self, + sp: Span, + mk_diag: M, + actual_ty: Ty<'tcx>, + ) -> Diag<'a> + where + M: FnOnce(String) -> Diag<'a>, + { + let actual_ty = self.resolve_vars_if_possible(actual_ty); + debug!("type_error_struct_with_diag({:?}, {:?})", sp, actual_ty); - pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>, + let mut err = mk_diag(self.ty_to_string(actual_ty)); - pub autoderef_steps: - Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>, -} + // Don't report an error if actual type is `Error`. + if actual_ty.references_error() { + err.downgrade_to_delayed_bug(); + } -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - pub fn dcx(&self) -> DiagCtxtHandle<'a> { - self.infcx.dcx() + err } - /// This is just to avoid a potential footgun of accidentally - /// dropping `typeck_results` by calling `InferCtxt::err_ctxt` - #[deprecated(note = "you already have a `TypeErrCtxt`")] - #[allow(unused)] - pub fn err_ctxt(&self) -> ! { - bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call"); + pub fn report_mismatched_types( + &self, + cause: &ObligationCause<'tcx>, + expected: Ty<'tcx>, + actual: Ty<'tcx>, + err: TypeError<'tcx>, + ) -> Diag<'a> { + self.report_and_explain_type_error(TypeTrace::types(cause, true, expected, actual), err) } -} -impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> { - type Target = InferCtxt<'tcx>; - fn deref(&self) -> &InferCtxt<'tcx> { - self.infcx + pub fn report_mismatched_consts( + &self, + cause: &ObligationCause<'tcx>, + expected: ty::Const<'tcx>, + actual: ty::Const<'tcx>, + err: TypeError<'tcx>, + ) -> Diag<'a> { + self.report_and_explain_type_error(TypeTrace::consts(cause, true, expected, actual), err) } -} -impl<'tcx> InferCtxt<'tcx> { pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { let (def_id, args) = match *ty.kind() { ty::Alias(_, ty::AliasTy { def_id, args, .. }) @@ -189,9 +198,7 @@ impl<'tcx> InferCtxt<'tcx> { .flatten() }) } -} -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Adds a note if the types come from similarly named crates fn check_and_note_conflicting_crates(&self, err: &mut Diag<'_>, terr: TypeError<'tcx>) { use hir::def_id::CrateNum; @@ -2190,32 +2197,3 @@ impl TyCategory { } } } - -impl<'tcx> InferCtxt<'tcx> { - /// Given a [`hir::Block`], get the span of its last expression or - /// statement, peeling off any inner blocks. - pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span { - let block = block.innermost_block(); - if let Some(expr) = &block.expr { - expr.span - } else if let Some(stmt) = block.stmts.last() { - // possibly incorrect trailing `;` in the else arm - stmt.span - } else { - // empty block; point at its entirety - block.span - } - } - - /// Given a [`hir::HirId`] for a block, get the span of its last expression - /// or statement, peeling off any inner blocks. - pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span { - match self.tcx.hir_node(hir_id) { - hir::Node::Block(blk) => self.find_block_span(blk), - // The parser was in a weird state if either of these happen, but - // it's better not to panic. - hir::Node::Expr(e) => e.span, - _ => rustc_span::DUMMY_SP, - } - } -} diff --git a/compiler/rustc_infer/src/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 4f3dcd9043f..56ea70bcf1d 100644 --- a/compiler/rustc_infer/src/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -1,4 +1,4 @@ -use crate::error_reporting::infer::TypeErrCtxt; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, SourceKindMultiSuggestion, SourceKindSubdiag, @@ -13,7 +13,6 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; -use rustc_middle::infer::unify_key::ConstVariableValue; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer}; use rustc_middle::ty::{ @@ -183,9 +182,7 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte warn!("resolved ty var in error message"); } - let mut infcx_inner = infcx.inner.borrow_mut(); - let ty_vars = infcx_inner.type_variables(); - let var_origin = ty_vars.var_origin(ty_vid); + let var_origin = infcx.type_var_origin(ty_vid); if let Some(def_id) = var_origin.param_def_id // The `Self` param of a trait has the def-id of the trait, // since it's a synthetic parameter. @@ -206,24 +203,8 @@ fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinte } }; printer.ty_infer_name_resolver = Some(Box::new(ty_getter)); - let const_getter = move |ct_vid| match infcx - .inner - .borrow_mut() - .const_unification_table() - .probe_value(ct_vid) - { - ConstVariableValue::Known { value: _ } => { - warn!("resolved const var in error message"); - None - } - ConstVariableValue::Unknown { origin, universe: _ } => { - if let Some(def_id) = origin.param_def_id { - Some(infcx.tcx.item_name(def_id)) - } else { - None - } - } - }; + let const_getter = + move |ct_vid| Some(infcx.tcx.item_name(infcx.const_var_origin(ct_vid)?.param_def_id?)); printer.const_infer_name_resolver = Some(Box::new(const_getter)); printer } @@ -289,7 +270,7 @@ fn closure_as_fn_str<'tcx>(infcx: &InferCtxt<'tcx>, ty: Ty<'tcx>) -> String { format!("fn({args}){ret}") } -impl<'tcx> InferCtxt<'tcx> { +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Extracts data used by diagnostic for either types or constants /// which were stuck during inference. pub fn extract_inference_diagnostics_data( @@ -300,9 +281,7 @@ impl<'tcx> InferCtxt<'tcx> { match arg.unpack() { GenericArgKind::Type(ty) => { if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { - let mut inner = self.inner.borrow_mut(); - let ty_vars = &inner.type_variables(); - let var_origin = ty_vars.var_origin(ty_vid); + let var_origin = self.infcx.type_var_origin(ty_vid); if let Some(def_id) = var_origin.param_def_id // The `Self` param of a trait has the def-id of the trait, // since it's a synthetic parameter. @@ -332,13 +311,7 @@ impl<'tcx> InferCtxt<'tcx> { } GenericArgKind::Const(ct) => { if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.kind() { - let origin = - match self.inner.borrow_mut().const_unification_table().probe_value(vid) { - ConstVariableValue::Known { value } => { - bug!("resolved infer var: {vid:?} {value}") - } - ConstVariableValue::Unknown { origin, universe: _ } => origin, - }; + let origin = self.const_var_origin(vid).expect("expected unresolved const var"); if let Some(def_id) = origin.param_def_id { return InferenceDiagnosticsData { name: self.tcx.item_name(def_id).to_string(), @@ -391,7 +364,7 @@ impl<'tcx> InferCtxt<'tcx> { span: Span, arg_data: InferenceDiagnosticsData, error_code: TypeAnnotationNeeded, - ) -> Diag<'_> { + ) -> Diag<'a> { let source_kind = "other"; let source_name = ""; let failure_span = None; @@ -434,9 +407,7 @@ impl<'tcx> InferCtxt<'tcx> { }), } } -} -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { #[instrument(level = "debug", skip(self, error_code))] pub fn emit_inference_failure_err( &self, @@ -453,7 +424,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // If we don't have any typeck results we're outside // of a body, so we won't be able to get better info // here. - return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code); + return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg); @@ -465,7 +436,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } let Some(InferSource { span, kind }) = local_visitor.infer_source else { - return self.infcx.bad_inference_failure_err(failure_span, arg_data, error_code); + return self.bad_inference_failure_err(failure_span, arg_data, error_code); }; let (source_kind, name, path) = kind.ty_localized_msg(self); @@ -887,7 +858,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { use ty::InferConst::*; match (inner_ct.kind(), target_ct.kind()) { (ty::ConstKind::Infer(Var(a_vid)), ty::ConstKind::Infer(Var(b_vid))) => { - self.tecx.inner.borrow_mut().const_unification_table().unioned(a_vid, b_vid) + self.tecx.root_const_var(a_vid) == self.tecx.root_const_var(b_vid) } _ => false, } diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs index 74dcde03639..74dcde03639 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/different_lifetimes.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/different_lifetimes.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs index b91b755d683..b91b755d683 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs index 550cc455e01..550cc455e01 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs index ced4c384f02..b83ecd8320c 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mod.rs @@ -1,4 +1,4 @@ -use crate::error_reporting::infer::TypeErrCtxt; +use crate::error_reporting::TypeErrCtxt; use crate::infer::RegionResolutionError; use crate::infer::RegionResolutionError::*; use rustc_errors::{Diag, ErrorGuaranteed}; diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs index d1802d2f5ee..d1802d2f5ee 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/named_anon_conflict.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs index 476ac3f1720..476ac3f1720 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_error.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs index e9f17a3e3e2..e9f17a3e3e2 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/placeholder_relation.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/placeholder_relation.rs diff --git a/compiler/rustc_infer/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 ce157ff3dc8..ce157ff3dc8 100644 --- a/compiler/rustc_infer/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 diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs index c58c7e13551..c58c7e13551 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs index 30fa98c5526..30fa98c5526 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/nice_region_error/util.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/note.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs index aeb3049c2ae..aeb3049c2ae 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/note.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs index d5e7de897d0..1ff2fca83fa 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs @@ -1,4 +1,3 @@ -use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diag, MultiSpan}; use rustc_hir as hir; @@ -12,6 +11,8 @@ use rustc_middle::{ }; use rustc_span::{def_id::DefId, sym, BytePos, Span, Symbol}; +use crate::error_reporting::TypeErrCtxt; + impl<'tcx> TypeErrCtxt<'_, 'tcx> { pub fn note_and_explain_type_err( &self, diff --git a/compiler/rustc_infer/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 5d41bb5d271..3cee8ff5f4c 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -18,7 +18,8 @@ use rustc_type_ir::Upcast as _; use super::nice_region_error::find_anon_type; use super::{nice_region_error, ObligationCauseAsDiagArg}; -use crate::error_reporting::infer::{ObligationCauseExt as _, TypeErrCtxt}; +use crate::error_reporting::infer::ObligationCauseExt as _; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ self, note_and_explain, FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData, RegionOriginNote, WhereClauseSuggestions, @@ -224,16 +225,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } .add_to_diag(err), infer::Reborrow(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err) + RegionOriginNote::Plain { span, msg: fluent::trait_selection_reborrow } + .add_to_diag(err) } infer::RelateObjectBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } + RegionOriginNote::Plain { span, msg: fluent::trait_selection_relate_object_bound } .add_to_diag(err); } infer::ReferenceOutlivesReferent(ty, span) => { RegionOriginNote::WithName { span, - msg: fluent::infer_reference_outlives_referent, + msg: fluent::trait_selection_reference_outlives_referent, name: &self.ty_to_string(ty), continues: false, } @@ -242,23 +244,32 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer::RelateParamBound(span, ty, opt_span) => { RegionOriginNote::WithName { span, - msg: fluent::infer_relate_param_bound, + msg: fluent::trait_selection_relate_param_bound, name: &self.ty_to_string(ty), continues: opt_span.is_some(), } .add_to_diag(err); if let Some(span) = opt_span { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } - .add_to_diag(err); + RegionOriginNote::Plain { + span, + msg: fluent::trait_selection_relate_param_bound_2, + } + .add_to_diag(err); } } infer::RelateRegionParamBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } - .add_to_diag(err); + RegionOriginNote::Plain { + span, + msg: fluent::trait_selection_relate_region_param_bound, + } + .add_to_diag(err); } infer::CompareImplItemObligation { span, .. } => { - RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } - .add_to_diag(err); + RegionOriginNote::Plain { + span, + msg: fluent::trait_selection_compare_impl_item_obligation, + } + .add_to_diag(err); } infer::CheckAssociatedTypeBounds { ref parent, .. } => { self.note_region_origin(err, parent); @@ -266,7 +277,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer::AscribeUserTypeProvePredicate(span) => { RegionOriginNote::Plain { span, - msg: fluent::infer_ascribe_user_type_prove_predicate, + msg: fluent::trait_selection_ascribe_user_type_prove_predicate, } .add_to_diag(err); } @@ -445,7 +456,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { - let mut err = self.infcx.report_extra_impl_obligation( + let mut err = self.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, @@ -645,7 +656,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_item_def_id, }) = origin { - return self.infcx.report_extra_impl_obligation( + return self.report_extra_impl_obligation( span, impl_item_def_id, trait_item_def_id, diff --git a/compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs index ef26a8ff7b8..ef26a8ff7b8 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/sub_relations.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/sub_relations.rs diff --git a/compiler/rustc_infer/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs index 4d11ab9fac6..1ef32d110b3 100644 --- a/compiler/rustc_infer/src/error_reporting/infer/suggest.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs @@ -17,14 +17,13 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt}; use rustc_span::{sym, Span}; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes, FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding, SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags, }; -use super::TypeErrCtxt; - #[derive(Clone, Copy)] pub enum SuggestAsRefKind { Option, diff --git a/compiler/rustc_trait_selection/src/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/mod.rs index f6ac8fc7b61..cb7efeaae0b 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/mod.rs @@ -1 +1,73 @@ +use std::ops::Deref; + +use rustc_errors::DiagCtxtHandle; +use rustc_infer::infer::InferCtxt; +use rustc_infer::traits::PredicateObligation; +use rustc_macros::extension; +use rustc_middle::bug; +use rustc_middle::ty::{self, Ty}; + +use crate::error_reporting::infer::sub_relations; + +pub mod infer; pub mod traits; + +/// A helper for building type related errors. The `typeck_results` +/// field is only populated during an in-progress typeck. +/// Get an instance by calling `InferCtxt::err_ctxt` or `FnCtxt::err_ctxt`. +/// +/// You must only create this if you intend to actually emit an error (or +/// perhaps a warning, though preferably not.) It provides a lot of utility +/// methods which should not be used during the happy path. +pub struct TypeErrCtxt<'a, 'tcx> { + pub infcx: &'a InferCtxt<'tcx>, + pub sub_relations: std::cell::RefCell<sub_relations::SubRelations>, + + pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>, + pub fallback_has_occurred: bool, + + pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>, + + pub autoderef_steps: + Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>, +} + +#[extension(pub trait InferCtxtErrorExt<'tcx>)] +impl<'tcx> InferCtxt<'tcx> { + /// Creates a `TypeErrCtxt` for emitting various inference errors. + /// During typeck, use `FnCtxt::err_ctxt` instead. + fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> { + TypeErrCtxt { + infcx: self, + sub_relations: Default::default(), + typeck_results: None, + fallback_has_occurred: false, + normalize_fn_sig: Box::new(|fn_sig| fn_sig), + autoderef_steps: Box::new(|ty| { + debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck"); + vec![(ty, vec![])] + }), + } + } +} + +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + pub fn dcx(&self) -> DiagCtxtHandle<'a> { + self.infcx.dcx() + } + + /// This is just to avoid a potential footgun of accidentally + /// dropping `typeck_results` by calling `InferCtxt::err_ctxt` + #[deprecated(note = "you already have a `TypeErrCtxt`")] + #[allow(unused)] + pub fn err_ctxt(&self) -> ! { + bug!("called `err_ctxt` on `TypeErrCtxt`. Try removing the call"); + } +} + +impl<'tcx> Deref for TypeErrCtxt<'_, 'tcx> { + type Target = InferCtxt<'tcx>; + fn deref(&self) -> &InferCtxt<'tcx> { + self.infcx + } +} 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 deab0451ccb..72a4d4c1205 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -8,21 +8,17 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor as _; use rustc_hir::LangItem; -use rustc_infer::error_reporting::infer::TypeErrCtxt; -use rustc_infer::infer::need_type_info::TypeAnnotationNeeded; use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt}; use rustc_infer::traits::util::elaborate; use rustc_infer::traits::{ Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation, }; -use rustc_macros::extension; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _}; use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP}; -use crate::error_reporting::traits::suggestions::TypeErrCtxtExt as _; -use crate::error_reporting::traits::{ - to_pretty_impl_header, FindExprBySpan, InferCtxtPrivExt as _, -}; +use crate::error_reporting::infer::need_type_info::TypeAnnotationNeeded; +use crate::error_reporting::traits::{to_pretty_impl_header, FindExprBySpan}; +use crate::error_reporting::TypeErrCtxt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::ObligationCtxt; @@ -153,10 +149,12 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>( ambiguities } -#[extension(pub trait TypeErrCtxtAmbiguityExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] - fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed { + pub(super) fn maybe_report_ambiguity( + &self, + obligation: &PredicateObligation<'tcx>, + ) -> ErrorGuaranteed { // Unable to successfully determine, probably means // insufficient type information, but could mean // ambiguous impls. The latter *ought* to be a 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 0d040ddbacb..85b37ff3260 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 @@ -1,6 +1,9 @@ -use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _}; -use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _}; +use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote}; +use super::suggestions::get_explanation_based_on_obligation; +use crate::error_reporting::infer::TyCategory; use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt; +use crate::error_reporting::traits::report_object_safety_error; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch, }; @@ -24,10 +27,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; use rustc_hir::{self as hir, LangItem}; -use rustc_infer::error_reporting::infer::TyCategory; -use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::infer::{InferOk, TypeTrace}; -use rustc_macros::extension; use rustc_middle::traits::select::OverflowError; use rustc_middle::traits::SignatureMismatchData; use rustc_middle::ty::abstract_const::NotConstEvaluatable; @@ -49,14 +49,11 @@ use super::{ ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst, }; -pub use rustc_infer::traits::error_reporting::*; - -#[extension(pub trait TypeErrCtxtSelectionErrExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// The `root_obligation` parameter should be the `root_obligation` field /// from a `FulfillmentError`. If no `FulfillmentError` is available, /// then it should be the same as `obligation`. - fn report_selection_error( + pub fn report_selection_error( &self, mut obligation: PredicateObligation<'tcx>, root_obligation: &PredicateObligation<'tcx>, @@ -682,9 +679,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } -#[extension(pub(super) trait TypeErrCtxtExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - fn apply_do_not_recommend(&self, obligation: &mut PredicateObligation<'tcx>) -> bool { + pub(super) fn apply_do_not_recommend( + &self, + obligation: &mut PredicateObligation<'tcx>, + ) -> bool { let mut base_cause = obligation.cause.code().clone(); let mut applied_do_not_recommend = false; loop { @@ -1142,7 +1141,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } -#[extension(pub(super) trait InferCtxtPrivExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn can_match_trait( &self, @@ -1182,7 +1180,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // returns if `cond` not occurring implies that `error` does not occur - i.e., that // `error` occurring implies that `cond` occurs. #[instrument(level = "debug", skip(self), ret)] - fn error_implies(&self, cond: ty::Predicate<'tcx>, error: ty::Predicate<'tcx>) -> bool { + pub(super) fn error_implies( + &self, + cond: ty::Predicate<'tcx>, + error: ty::Predicate<'tcx>, + ) -> bool { if cond == error { return true; } @@ -1205,7 +1207,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip_all)] - fn report_projection_error( + pub(super) fn report_projection_error( &self, obligation: &PredicateObligation<'tcx>, error: &MismatchedProjectionTypes<'tcx>, @@ -1455,7 +1457,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn fuzzy_match_tys( + pub fn fuzzy_match_tys( &self, mut a: Ty<'tcx>, mut b: Ty<'tcx>, @@ -1535,7 +1537,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str { + pub(super) fn describe_closure(&self, kind: hir::ClosureKind) -> &'static str { match kind { hir::ClosureKind::Closure => "a closure", hir::ClosureKind::Coroutine(hir::CoroutineKind::Coroutine(_)) => "a coroutine", @@ -1585,7 +1587,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn find_similar_impl_candidates( + pub(super) fn find_similar_impl_candidates( &self, trait_pred: ty::PolyTraitPredicate<'tcx>, ) -> Vec<ImplCandidate<'tcx>> { @@ -1615,7 +1617,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { candidates } - fn report_similar_impl_candidates( + pub(super) fn report_similar_impl_candidates( &self, impl_candidates: &[ImplCandidate<'tcx>], trait_ref: ty::PolyTraitRef<'tcx>, @@ -1989,7 +1991,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// `trait_ref`. /// /// For this to work, `new_self_ty` must have no escaping bound variables. - fn mk_trait_obligation_with_new_self_ty( + pub(super) fn mk_trait_obligation_with_new_self_ty( &self, param_env: ty::ParamEnv<'tcx>, trait_ref_and_ty: ty::Binder<'tcx, (ty::TraitPredicate<'tcx>, Ty<'tcx>)>, @@ -2041,7 +2043,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } - fn note_obligation_cause(&self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>) { + pub fn note_obligation_cause( + &self, + err: &mut Diag<'_>, + obligation: &PredicateObligation<'tcx>, + ) { // First, attempt to add note to this error with an async-await-specific // message, and fall back to regular note otherwise. if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { @@ -2067,7 +2073,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn is_recursive_obligation( + pub(super) fn is_recursive_obligation( &self, obligated_types: &mut Vec<Ty<'tcx>>, cause_code: &ObligationCauseCode<'tcx>, 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 16dfa27b75a..10624786bae 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -5,28 +5,24 @@ pub mod on_unimplemented; mod overflow; pub mod suggestions; -use std::iter; +use std::{fmt, iter}; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; -use rustc_hir::def_id::DefId; +use rustc_errors::{struct_span_code_err, Applicability, Diag, MultiSpan, E0038, E0276}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem}; -use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::traits::{ - Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, + ObjectSafetyViolation, Obligation, ObligationCause, ObligationCauseCode, PredicateObligation, + SelectionError, }; -use rustc_macros::extension; -use rustc_middle::ty::print::PrintTraitRefExt as _; +use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::{ErrorGuaranteed, ExpnKind, Span}; -use ambiguity::TypeErrCtxtAmbiguityExt as _; -use fulfillment_errors::TypeErrCtxtExt as _; -use suggestions::TypeErrCtxtExt as _; - +use crate::error_reporting::TypeErrCtxt; use crate::traits::{FulfillmentError, FulfillmentErrorCode}; -pub use self::fulfillment_errors::*; pub use self::infer_ctxt_ext::*; pub use self::overflow::*; @@ -137,9 +133,8 @@ pub enum DefIdOrName { Name(&'static str), } -#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - fn report_fulfillment_errors( + pub fn report_fulfillment_errors( &self, mut errors: Vec<FulfillmentError<'tcx>>, ) -> ErrorGuaranteed { @@ -383,3 +378,194 @@ pub(crate) fn to_pretty_impl_header(tcx: TyCtxt<'_>, impl_def_id: DefId) -> Opti w.push(';'); Some(w) } + +impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { + pub fn report_extra_impl_obligation( + &self, + error_span: Span, + impl_item_def_id: LocalDefId, + trait_item_def_id: DefId, + requirement: &dyn fmt::Display, + ) -> Diag<'a> { + let mut err = struct_span_code_err!( + self.dcx(), + error_span, + E0276, + "impl has stricter requirements than trait" + ); + + if !self.tcx.is_impl_trait_in_trait(trait_item_def_id) { + if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) { + let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); + err.span_label(span, format!("definition of `{item_name}` from trait")); + } + } + + err.span_label(error_span, format!("impl has extra requirement {requirement}")); + + err + } +} + +pub fn report_object_safety_error<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + hir_id: Option<hir::HirId>, + trait_def_id: DefId, + violations: &[ObjectSafetyViolation], +) -> Diag<'tcx> { + let trait_str = tcx.def_path_str(trait_def_id); + let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node { + 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", + 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, + ); + } + } + let mut reported_violations = FxIndexSet::default(); + let mut multi_span = vec![]; + let mut messages = vec![]; + for violation in violations { + if let ObjectSafetyViolation::SizedSelf(sp) = &violation + && !sp.is_empty() + { + // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations + // with a `Span`. + reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into())); + } + 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()) + } else { + format!("...because {}", violation.error_msg()) + }; + if spans.is_empty() { + err.note(msg); + } else { + for span in spans { + multi_span.push(span); + messages.push(msg.clone()); + } + } + } + } + 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..."); + } + for (span, msg) in iter::zip(multi_span, messages) { + note_span.push_span_label(span, msg); + } + err.span_note( + note_span, + "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \ + to be resolvable dynamically; for more information visit \ + <https://doc.rust-lang.org/reference/items/traits.html#object-safety>", + ); + + // 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(); + // Allows us to skip suggesting that the same item should be moved to another trait multiple times. + potential_solutions.dedup(); + for solution in potential_solutions { + solution.add_to(&mut err); + } + } + + 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() + // 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 + } 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 externally_visible { + err.note(format!( + "`{trait_str}` 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", + )); + } + + err +} 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 a448e1924c8..f65de590ccf 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 @@ -1,5 +1,5 @@ use super::{ObligationCauseCode, PredicateObligation}; -use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt; +use crate::error_reporting::TypeErrCtxt; use crate::errors::{ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented, }; @@ -13,8 +13,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_infer::error_reporting::infer::TypeErrCtxt; -use rustc_macros::{extension, LintDiagnostic}; +use rustc_macros::LintDiagnostic; use rustc_middle::bug; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::GenericArgsRef; @@ -41,7 +40,6 @@ static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[ sym::Trait, ]; -#[extension(pub trait TypeErrCtxtExt<'tcx>)] impl<'tcx> TypeErrCtxt<'_, 'tcx> { fn impl_similar_to( &self, @@ -109,7 +107,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { } } - fn on_unimplemented_note( + pub fn on_unimplemented_note( &self, trait_ref: ty::PolyTraitRef<'tcx>, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index fe1771f9096..16fbff7816a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -5,17 +5,14 @@ use rustc_errors::{ }; use rustc_hir::def::Namespace; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_infer::error_reporting::infer::TypeErrCtxt; use rustc_infer::traits::{Obligation, PredicateObligation}; -use rustc_macros::extension; use rustc_middle::ty::print::{FmtPrinter, Print}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::Limit; use rustc_span::Span; use rustc_type_ir::Upcast; -use super::InferCtxtPrivExt; -use crate::error_reporting::traits::suggestions::TypeErrCtxtExt; +use crate::error_reporting::TypeErrCtxt; pub enum OverflowCause<'tcx> { DeeplyNormalize(ty::AliasTerm<'tcx>), @@ -38,7 +35,6 @@ pub fn suggest_new_overflow_limit<'tcx, G: EmissionGuarantee>( )); } -#[extension(pub trait TypeErrCtxtOverflowExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Reports that an overflow has occurred and halts compilation. We /// halt compilation unconditionally because it is important that @@ -46,7 +42,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// whose result could not be truly determined and thus we can't say /// if the program type checks or not -- and they are unusual /// occurrences in any case. - fn report_overflow_error( + pub fn report_overflow_error( &self, cause: OverflowCause<'tcx>, span: Span, @@ -59,7 +55,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { FatalError.raise(); } - fn build_overflow_error( + pub fn build_overflow_error( &self, cause: OverflowCause<'tcx>, span: Span, @@ -132,7 +128,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// whose result could not be truly determined and thus we can't say /// if the program type checks or not -- and they are unusual /// occurrences in any case. - fn report_overflow_obligation<T>( + pub fn report_overflow_obligation<T>( &self, obligation: &Obligation<'tcx, T>, suggest_increasing_limit: bool, @@ -165,7 +161,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// that we can give a more helpful error message (and, in particular, /// we do not suggest increasing the overflow limit, which is not /// going to help). - fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { + pub fn report_overflow_obligation_cycle(&self, cycle: &[PredicateObligation<'tcx>]) -> ! { let cycle = self.resolve_vars_if_possible(cycle.to_owned()); assert!(!cycle.is_empty()); @@ -179,7 +175,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn report_overflow_no_abort( + pub fn report_overflow_no_abort( &self, obligation: PredicateObligation<'tcx>, suggest_increasing_limit: bool, 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 ffc8839435e..885216e6216 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -5,11 +5,10 @@ use super::{ PredicateObligation, }; +use crate::error_reporting::TypeErrCtxt; use crate::errors; -use crate::infer::InferCtxt; use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt}; -use hir::def::CtorOf; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ @@ -17,15 +16,15 @@ use rustc_errors::{ Style, SuggestionStyle, }; use rustc_hir as hir; +use rustc_hir::def::CtorOf; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; use rustc_hir::is_range_literal; use rustc_hir::lang_items::LangItem; use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node}; -use rustc_infer::error_reporting::infer::TypeErrCtxt; +use rustc_infer::infer::InferCtxt; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk}; -use rustc_macros::extension; use rustc_middle::hir::map; use rustc_middle::traits::IsConstable; use rustc_middle::ty::error::TypeError; @@ -44,7 +43,6 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; -use crate::error_reporting::traits::fulfillment_errors::InferCtxtPrivExt; use crate::infer::InferCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_middle::ty::print::{ @@ -241,9 +239,8 @@ pub fn suggest_restriction<'tcx, G: EmissionGuarantee>( } } -#[extension(pub trait TypeErrCtxtExt<'a, 'tcx>)] impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - fn suggest_restricting_param_bound( + pub fn suggest_restricting_param_bound( &self, err: &mut Diag<'_>, trait_pred: ty::PolyTraitPredicate<'tcx>, @@ -453,7 +450,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// When after several dereferencing, the reference satisfies the trait /// bound. This function provides dereference suggestion for this /// specific situation. - fn suggest_dereferences( + pub(super) fn suggest_dereferences( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -782,7 +779,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// We tried to apply the bound to an `fn` or closure. Check whether calling it would /// evaluate to a type that *would* satisfy the trait bound. If it would, suggest calling /// it: `bar(foo)` → `bar(foo())`. This case is *very* likely to be hit if `foo` is `async`. - fn suggest_fn_call( + pub(super) fn suggest_fn_call( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -898,7 +895,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true } - fn check_for_binding_assigned_block_without_tail_expression( + pub(super) fn check_for_binding_assigned_block_without_tail_expression( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -974,7 +971,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_add_clone_to_arg( + pub(super) fn suggest_add_clone_to_arg( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1074,7 +1071,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Extracts information about a callable type for diagnostics. This is a /// heuristic -- it doesn't necessarily mean that a type is always callable, /// because the callable type must also be well-formed to be called. - fn extract_callable_info( + pub fn extract_callable_info( &self, body_id: LocalDefId, param_env: ty::ParamEnv<'tcx>, @@ -1200,7 +1197,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if output.is_ty_var() { None } else { Some((def_id_or_name, output, inputs)) } } - fn suggest_add_reference_to_arg( + pub(super) fn suggest_add_reference_to_arg( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1422,7 +1419,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } // Suggest borrowing the type - fn suggest_borrowing_for_object_cast( + pub(super) fn suggest_borrowing_for_object_cast( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -1457,7 +1454,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, /// suggest removing these references until we reach a type that implements the trait. - fn suggest_remove_reference( + pub(super) fn suggest_remove_reference( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1578,7 +1575,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false } - fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>) { + pub(super) fn suggest_remove_await( + &self, + obligation: &PredicateObligation<'tcx>, + err: &mut Diag<'_>, + ) { let hir = self.tcx.hir(); if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id) @@ -1644,7 +1645,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// Check if the trait bound is implemented for a different mutability and note it in the /// final error. - fn suggest_change_mut( + pub(super) fn suggest_change_mut( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1720,7 +1721,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_semicolon_removal( + pub(super) fn suggest_semicolon_removal( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -1762,7 +1763,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { false } - fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> { + pub(super) fn return_type_span(&self, obligation: &PredicateObligation<'tcx>) -> Option<Span> { let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(sig, ..), .. }) = self.tcx.hir_node_by_def_id(obligation.cause.body_id) else { @@ -1775,7 +1776,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// If all conditions are met to identify a returned `dyn Trait`, suggest using `impl Trait` if /// applicable and signal that the error has been expanded appropriately and needs to be /// emitted. - fn suggest_impl_trait( + pub(super) fn suggest_impl_trait( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -1865,7 +1866,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { true } - fn point_at_returns_when_relevant( + pub(super) fn point_at_returns_when_relevant( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -1897,7 +1898,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn report_closure_arg_mismatch( + pub(super) fn report_closure_arg_mismatch( &self, span: Span, found_span: Option<Span>, @@ -2176,7 +2177,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_fully_qualified_path( + pub(super) fn suggest_fully_qualified_path( &self, err: &mut Diag<'_>, item_def_id: DefId, @@ -2243,7 +2244,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// /// Returns `true` if an async-await specific note was added to the diagnostic. #[instrument(level = "debug", skip_all, fields(?obligation.predicate, ?obligation.cause.span))] - fn maybe_note_obligation_cause_for_async_await<G: EmissionGuarantee>( + pub fn maybe_note_obligation_cause_for_async_await<G: EmissionGuarantee>( &self, err: &mut Diag<'_, G>, obligation: &PredicateObligation<'tcx>, @@ -2712,7 +2713,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn note_obligation_cause_code<G: EmissionGuarantee, T>( + pub(super) fn note_obligation_cause_code<G: EmissionGuarantee, T>( &self, body_id: LocalDefId, err: &mut Diag<'_, G>, @@ -3554,7 +3555,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { #[instrument( level = "debug", skip(self, err), fields(trait_pred.self_ty = ?trait_pred.self_ty()) )] - fn suggest_await_before_try( + pub(super) fn suggest_await_before_try( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -3611,7 +3612,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_floating_point_literal( + pub(super) fn suggest_floating_point_literal( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -3635,7 +3636,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_derive( + pub fn suggest_derive( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -3701,7 +3702,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_dereferencing_index( + pub(super) fn suggest_dereferencing_index( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -4323,7 +4324,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { /// If the type that failed selection is an array or a reference to an array, /// but the trait is implemented for slices, suggest that the user converts /// the array into a slice. - fn suggest_convert_to_slice( + pub(super) fn suggest_convert_to_slice( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, @@ -4395,7 +4396,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn explain_hrtb_projection( + pub(super) fn explain_hrtb_projection( &self, diag: &mut Diag<'_>, pred: ty::PolyTraitPredicate<'tcx>, @@ -4461,7 +4462,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } } - fn suggest_desugaring_async_fn_in_trait( + pub(super) fn suggest_desugaring_async_fn_in_trait( &self, err: &mut Diag<'_>, trait_ref: ty::PolyTraitRef<'tcx>, @@ -4545,7 +4546,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ); } - fn ty_kind_suggestion(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> Option<String> { + pub fn ty_kind_suggestion( + &self, + param_env: ty::ParamEnv<'tcx>, + ty: Ty<'tcx>, + ) -> Option<String> { let tcx = self.infcx.tcx; let implements_default = |ty| { let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else { @@ -4607,7 +4612,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) } - fn suggest_add_result_as_return_type( + pub(super) fn suggest_add_result_as_return_type( &self, obligation: &PredicateObligation<'tcx>, err: &mut Diag<'_>, @@ -4648,7 +4653,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } #[instrument(level = "debug", skip_all)] - fn suggest_unsized_bound_if_applicable( + pub(super) fn suggest_unsized_bound_if_applicable( &self, err: &mut Diag<'_>, obligation: &PredicateObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs index a46cba35b2d..0ee4485a365 100644 --- a/compiler/rustc_trait_selection/src/errors.rs +++ b/compiler/rustc_trait_selection/src/errors.rs @@ -1,11 +1,30 @@ -use crate::fluent_generated as fluent; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - codes::*, Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, - SubdiagMessageOp, Subdiagnostic, + codes::*, Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic, + EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic, }; +use rustc_hir as hir; +use rustc_hir::def_id::LocalDefId; +use rustc_hir::intravisit::{walk_ty, Visitor}; +use rustc_hir::FnRetTy; +use rustc_hir::GenericParamKind; use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::{self, print::PrintTraitRefExt as _, ClosureKind, PolyTraitRef, Ty}; -use rustc_span::{Span, Symbol}; +use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath; +use rustc_middle::ty::{ + self, print::PrintTraitRefExt as _, Binder, ClosureKind, FnSig, PolyTraitRef, Region, Ty, + TyCtxt, +}; +use rustc_span::symbol::{kw, Ident, Symbol}; +use rustc_span::{BytePos, Span}; + +use crate::error_reporting::infer::need_type_info::UnderspecifiedArgKind; +use crate::error_reporting::infer::nice_region_error::placeholder_error::Highlighted; +use crate::error_reporting::infer::ObligationCauseAsDiagArg; +use crate::fluent_generated as fluent; + +use std::path::PathBuf; + +pub mod note_and_explain; #[derive(Diagnostic)] #[diag(trait_selection_dump_vtable_entries)] @@ -170,3 +189,1613 @@ pub(crate) struct AsyncClosureNotFn { pub span: Span, pub kind: &'static str, } + +#[derive(Diagnostic)] +#[diag(trait_selection_type_annotations_needed, code = E0282)] +pub struct AnnotationRequired<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option<Span>, + #[subdiagnostic] + pub bad_label: Option<InferenceBadError<'a>>, + #[subdiagnostic] + pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, + #[subdiagnostic] + pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, + #[note(trait_selection_full_type_written)] + pub was_written: Option<()>, + pub path: PathBuf, +} + +// Copy of `AnnotationRequired` for E0283 +#[derive(Diagnostic)] +#[diag(trait_selection_type_annotations_needed, code = E0283)] +pub struct AmbiguousImpl<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option<Span>, + #[subdiagnostic] + pub bad_label: Option<InferenceBadError<'a>>, + #[subdiagnostic] + pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, + #[subdiagnostic] + pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, + #[note(trait_selection_full_type_written)] + pub was_written: Option<()>, + pub path: PathBuf, +} + +// Copy of `AnnotationRequired` for E0284 +#[derive(Diagnostic)] +#[diag(trait_selection_type_annotations_needed, code = E0284)] +pub struct AmbiguousReturn<'a> { + #[primary_span] + pub span: Span, + pub source_kind: &'static str, + pub source_name: &'a str, + #[label] + pub failure_span: Option<Span>, + #[subdiagnostic] + pub bad_label: Option<InferenceBadError<'a>>, + #[subdiagnostic] + pub infer_subdiags: Vec<SourceKindSubdiag<'a>>, + #[subdiagnostic] + pub multi_suggestions: Vec<SourceKindMultiSuggestion<'a>>, + #[note(trait_selection_full_type_written)] + pub was_written: Option<()>, + pub path: PathBuf, +} + +// Used when a better one isn't available +#[derive(Subdiagnostic)] +#[label(trait_selection_label_bad)] +pub struct InferenceBadError<'a> { + #[primary_span] + pub span: Span, + pub bad_kind: &'static str, + pub prefix_kind: UnderspecifiedArgKind, + pub has_parent: bool, + pub prefix: &'a str, + pub parent_prefix: &'a str, + pub parent_name: String, + pub name: String, +} + +#[derive(Subdiagnostic)] +pub enum SourceKindSubdiag<'a> { + #[suggestion( + trait_selection_source_kind_subdiag_let, + style = "verbose", + code = ": {type_name}", + applicability = "has-placeholders" + )] + LetLike { + #[primary_span] + span: Span, + name: String, + type_name: String, + kind: &'static str, + x_kind: &'static str, + prefix_kind: UnderspecifiedArgKind, + prefix: &'a str, + arg_name: String, + }, + #[label(trait_selection_source_kind_subdiag_generic_label)] + GenericLabel { + #[primary_span] + span: Span, + is_type: bool, + param_name: String, + parent_exists: bool, + parent_prefix: String, + parent_name: String, + }, + #[suggestion( + trait_selection_source_kind_subdiag_generic_suggestion, + style = "verbose", + code = "::<{args}>", + applicability = "has-placeholders" + )] + GenericSuggestion { + #[primary_span] + span: Span, + arg_count: usize, + args: String, + }, +} + +#[derive(Subdiagnostic)] +pub enum SourceKindMultiSuggestion<'a> { + #[multipart_suggestion( + trait_selection_source_kind_fully_qualified, + style = "verbose", + applicability = "has-placeholders" + )] + FullyQualified { + #[suggestion_part(code = "{def_path}({adjustment}")] + span_lo: Span, + #[suggestion_part(code = "{successor_pos}")] + span_hi: Span, + def_path: String, + adjustment: &'a str, + successor_pos: &'a str, + }, + #[multipart_suggestion( + trait_selection_source_kind_closure_return, + style = "verbose", + applicability = "has-placeholders" + )] + ClosureReturn { + #[suggestion_part(code = "{start_span_code}")] + start_span: Span, + start_span_code: String, + #[suggestion_part(code = " }}")] + end_span: Option<Span>, + }, +} + +impl<'a> SourceKindMultiSuggestion<'a> { + pub fn new_fully_qualified( + span: Span, + def_path: String, + adjustment: &'a str, + successor: (&'a str, BytePos), + ) -> Self { + Self::FullyQualified { + span_lo: span.shrink_to_lo(), + span_hi: span.shrink_to_hi().with_hi(successor.1), + def_path, + adjustment, + successor_pos: successor.0, + } + } + + pub fn new_closure_return( + ty_info: String, + data: &'a FnRetTy<'a>, + should_wrap_expr: Option<Span>, + ) -> Self { + let arrow = match data { + FnRetTy::DefaultReturn(_) => " -> ", + _ => "", + }; + let (start_span, start_span_code, end_span) = match should_wrap_expr { + Some(end_span) => (data.span(), format!("{arrow}{ty_info} {{"), Some(end_span)), + None => (data.span(), format!("{arrow}{ty_info}"), None), + }; + Self::ClosureReturn { start_span, start_span_code, end_span } + } +} + +pub enum RegionOriginNote<'a> { + Plain { + span: Span, + msg: DiagMessage, + }, + WithName { + span: Span, + msg: DiagMessage, + name: &'a str, + continues: bool, + }, + WithRequirement { + span: Span, + requirement: ObligationCauseAsDiagArg<'a>, + expected_found: Option<(DiagStyledString, DiagStyledString)>, + }, +} + +impl Subdiagnostic for RegionOriginNote<'_> { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + let mut label_or_note = |span, msg: DiagMessage| { + let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count(); + let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count(); + let span_is_primary = diag.span.primary_spans().iter().all(|&sp| sp == span); + if span_is_primary && sub_count == 0 && expanded_sub_count == 0 { + diag.span_label(span, msg); + } else if span_is_primary && expanded_sub_count == 0 { + diag.note(msg); + } else { + diag.span_note(span, msg); + } + }; + match self { + RegionOriginNote::Plain { span, msg } => { + label_or_note(span, msg); + } + RegionOriginNote::WithName { span, msg, name, continues } => { + label_or_note(span, msg); + diag.arg("name", name); + diag.arg("continues", continues); + } + RegionOriginNote::WithRequirement { + span, + requirement, + expected_found: Some((expected, found)), + } => { + label_or_note(span, fluent::trait_selection_subtype); + diag.arg("requirement", requirement); + + diag.note_expected_found(&"", expected, &"", found); + } + RegionOriginNote::WithRequirement { span, requirement, expected_found: None } => { + // FIXME: this really should be handled at some earlier stage. Our + // handling of region checking when type errors are present is + // *terrible*. + label_or_note(span, fluent::trait_selection_subtype_2); + diag.arg("requirement", requirement); + } + }; + } +} + +pub enum LifetimeMismatchLabels { + InRet { + param_span: Span, + ret_span: Span, + span: Span, + label_var1: Option<Ident>, + }, + Normal { + hir_equal: bool, + ty_sup: Span, + ty_sub: Span, + span: Span, + sup: Option<Ident>, + sub: Option<Ident>, + }, +} + +impl Subdiagnostic for LifetimeMismatchLabels { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + match self { + LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => { + diag.span_label(param_span, fluent::trait_selection_declared_different); + diag.span_label(ret_span, fluent::trait_selection_nothing); + diag.span_label(span, fluent::trait_selection_data_returned); + diag.arg("label_var1_exists", label_var1.is_some()); + diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); + } + LifetimeMismatchLabels::Normal { + hir_equal, + ty_sup, + ty_sub, + span, + sup: label_var1, + sub: label_var2, + } => { + if hir_equal { + diag.span_label(ty_sup, fluent::trait_selection_declared_multiple); + diag.span_label(ty_sub, fluent::trait_selection_nothing); + diag.span_label(span, fluent::trait_selection_data_lifetime_flow); + } else { + diag.span_label(ty_sup, fluent::trait_selection_types_declared_different); + diag.span_label(ty_sub, fluent::trait_selection_nothing); + diag.span_label(span, fluent::trait_selection_data_flows); + diag.arg("label_var1_exists", label_var1.is_some()); + diag.arg("label_var1", label_var1.map(|x| x.to_string()).unwrap_or_default()); + diag.arg("label_var2_exists", label_var2.is_some()); + diag.arg("label_var2", label_var2.map(|x| x.to_string()).unwrap_or_default()); + } + } + } + } +} + +pub struct AddLifetimeParamsSuggestion<'a> { + pub tcx: TyCtxt<'a>, + pub generic_param_scope: LocalDefId, + pub sub: Region<'a>, + pub ty_sup: &'a hir::Ty<'a>, + pub ty_sub: &'a hir::Ty<'a>, + pub add_note: bool, +} + +impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + let mut mk_suggestion = || { + let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub) + else { + return false; + }; + + let node = self.tcx.hir_node_by_def_id(anon_reg.def_id); + let is_impl = matches!(&node, hir::Node::ImplItem(_)); + let (generics, parent_generics) = match node { + hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Fn(_, ref generics, ..), + .. + }) + | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. }) + | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => ( + generics, + match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id)) + { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, ref generics, ..), + .. + }) + | hir::Node::Item(hir::Item { + kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }), + .. + }) => Some(generics), + _ => None, + }, + ), + _ => return false, + }; + + let suggestion_param_name = generics + .params + .iter() + .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .map(|p| p.name.ident().name) + .find(|i| *i != kw::UnderscoreLifetime); + let introduce_new = suggestion_param_name.is_none(); + + let mut default = "'a".to_string(); + if let Some(parent_generics) = parent_generics { + let used: FxHashSet<_> = parent_generics + .params + .iter() + .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. })) + .map(|p| p.name.ident().name) + .filter(|i| *i != kw::UnderscoreLifetime) + .map(|l| l.to_string()) + .collect(); + if let Some(lt) = + ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it)) + { + // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc + // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is + // likely to be an over-constraining lifetime requirement, so we always add a + // lifetime to the `fn`. + default = lt; + } + } + let suggestion_param_name = + suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default); + + struct ImplicitLifetimeFinder { + suggestions: Vec<(Span, String)>, + suggestion_param_name: String, + } + + impl<'v> Visitor<'v> for ImplicitLifetimeFinder { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + let make_suggestion = |ident: Ident| { + if ident.name == kw::Empty && ident.span.is_empty() { + format!("{}, ", self.suggestion_param_name) + } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() { + format!("{} ", self.suggestion_param_name) + } else { + self.suggestion_param_name.clone() + } + }; + match ty.kind { + hir::TyKind::Path(hir::QPath::Resolved(_, path)) => { + for segment in path.segments { + if let Some(args) = segment.args { + if args.args.iter().all(|arg| { + matches!( + arg, + hir::GenericArg::Lifetime(lifetime) + if lifetime.ident.name == kw::Empty + ) + }) { + self.suggestions.push(( + segment.ident.span.shrink_to_hi(), + format!( + "<{}>", + args.args + .iter() + .map(|_| self.suggestion_param_name.clone()) + .collect::<Vec<_>>() + .join(", ") + ), + )); + } else { + for arg in args.args { + if let hir::GenericArg::Lifetime(lifetime) = arg + && lifetime.is_anonymous() + { + self.suggestions.push(( + lifetime.ident.span, + make_suggestion(lifetime.ident), + )); + } + } + } + } + } + } + hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => { + self.suggestions + .push((lifetime.ident.span, make_suggestion(lifetime.ident))); + } + _ => {} + } + walk_ty(self, ty); + } + } + let mut visitor = ImplicitLifetimeFinder { + suggestions: vec![], + suggestion_param_name: suggestion_param_name.clone(), + }; + if let Some(fn_decl) = node.fn_decl() + && let hir::FnRetTy::Return(ty) = fn_decl.output + { + visitor.visit_ty(ty); + } + if visitor.suggestions.is_empty() { + // Do not suggest constraining the `&self` param, but rather the return type. + // If that is wrong (because it is not sufficient), a follow up error will tell the + // user to fix it. This way we lower the chances of *over* constraining, but still + // get the cake of "correctly" contrained in two steps. + visitor.visit_ty(self.ty_sup); + } + visitor.visit_ty(self.ty_sub); + if visitor.suggestions.is_empty() { + return false; + } + if introduce_new { + let new_param_suggestion = if let Some(first) = + generics.params.iter().find(|p| !p.name.ident().span.is_empty()) + { + (first.span.shrink_to_lo(), format!("{suggestion_param_name}, ")) + } else { + (generics.span, format!("<{suggestion_param_name}>")) + }; + + visitor.suggestions.push(new_param_suggestion); + } + diag.multipart_suggestion_verbose( + fluent::trait_selection_lifetime_param_suggestion, + visitor.suggestions, + Applicability::MaybeIncorrect, + ); + diag.arg("is_impl", is_impl); + diag.arg("is_reuse", !introduce_new); + + true + }; + if mk_suggestion() && self.add_note { + diag.note(fluent::trait_selection_lifetime_param_suggestion_elided); + } + } +} + +#[derive(Diagnostic)] +#[diag(trait_selection_lifetime_mismatch, code = E0623)] +pub struct LifetimeMismatch<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub labels: LifetimeMismatchLabels, + #[subdiagnostic] + pub suggestion: AddLifetimeParamsSuggestion<'a>, +} + +pub struct IntroducesStaticBecauseUnmetLifetimeReq { + pub unmet_requirements: MultiSpan, + pub binding_span: Span, +} + +impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + mut self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + self.unmet_requirements + .push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static); + diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req); + } +} + +// FIXME(#100717): replace with a `Option<Span>` when subdiagnostic supports that +#[derive(Subdiagnostic)] +pub enum DoesNotOutliveStaticFromImpl { + #[note(trait_selection_does_not_outlive_static_from_impl)] + Spanned { + #[primary_span] + span: Span, + }, + #[note(trait_selection_does_not_outlive_static_from_impl)] + Unspanned, +} + +#[derive(Subdiagnostic)] +pub enum ImplicitStaticLifetimeSubdiag { + #[note(trait_selection_implicit_static_lifetime_note)] + Note { + #[primary_span] + span: Span, + }, + #[suggestion( + trait_selection_implicit_static_lifetime_suggestion, + style = "verbose", + code = " + '_", + applicability = "maybe-incorrect" + )] + Sugg { + #[primary_span] + span: Span, + }, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_mismatched_static_lifetime)] +pub struct MismatchedStaticLifetime<'a> { + #[primary_span] + pub cause_span: Span, + #[subdiagnostic] + pub unmet_lifetime_reqs: IntroducesStaticBecauseUnmetLifetimeReq, + #[subdiagnostic] + pub expl: Option<note_and_explain::RegionExplanation<'a>>, + #[subdiagnostic] + pub does_not_outlive_static_from_impl: DoesNotOutliveStaticFromImpl, + #[subdiagnostic] + pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>, +} + +#[derive(Diagnostic)] +pub enum ExplicitLifetimeRequired<'a> { + #[diag(trait_selection_explicit_lifetime_required_with_ident, code = E0621)] + WithIdent { + #[primary_span] + #[label] + span: Span, + simple_ident: Ident, + named: String, + #[suggestion( + trait_selection_explicit_lifetime_required_sugg_with_ident, + code = "{new_ty}", + applicability = "unspecified" + )] + new_ty_span: Span, + #[skip_arg] + new_ty: Ty<'a>, + }, + #[diag(trait_selection_explicit_lifetime_required_with_param_type, code = E0621)] + WithParamType { + #[primary_span] + #[label] + span: Span, + named: String, + #[suggestion( + trait_selection_explicit_lifetime_required_sugg_with_param_type, + code = "{new_ty}", + applicability = "unspecified" + )] + new_ty_span: Span, + #[skip_arg] + new_ty: Ty<'a>, + }, +} + +pub enum TyOrSig<'tcx> { + Ty(Highlighted<'tcx, Ty<'tcx>>), + ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>), +} + +impl IntoDiagArg for TyOrSig<'_> { + fn into_diag_arg(self) -> rustc_errors::DiagArgValue { + match self { + TyOrSig::Ty(ty) => ty.into_diag_arg(), + TyOrSig::ClosureSig(sig) => sig.into_diag_arg(), + } + } +} + +#[derive(Subdiagnostic)] +pub enum ActualImplExplNotes<'tcx> { + #[note(trait_selection_actual_impl_expl_expected_signature_two)] + ExpectedSignatureTwo { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_signature_any)] + ExpectedSignatureAny { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_signature_some)] + ExpectedSignatureSome { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_signature_nothing)] + ExpectedSignatureNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, + #[note(trait_selection_actual_impl_expl_expected_passive_two)] + ExpectedPassiveTwo { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_passive_any)] + ExpectedPassiveAny { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_passive_some)] + ExpectedPassiveSome { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_passive_nothing)] + ExpectedPassiveNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, + #[note(trait_selection_actual_impl_expl_expected_other_two)] + ExpectedOtherTwo { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_other_any)] + ExpectedOtherAny { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_other_some)] + ExpectedOtherSome { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + }, + #[note(trait_selection_actual_impl_expl_expected_other_nothing)] + ExpectedOtherNothing { + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + }, + #[note(trait_selection_actual_impl_expl_but_actually_implements_trait)] + ButActuallyImplementsTrait { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + }, + #[note(trait_selection_actual_impl_expl_but_actually_implemented_for_ty)] + ButActuallyImplementedForTy { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + ty: String, + }, + #[note(trait_selection_actual_impl_expl_but_actually_ty_implements)] + ButActuallyTyImplements { + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + has_lifetime: bool, + lifetime: usize, + ty: String, + }, +} + +pub enum ActualImplExpectedKind { + Signature, + Passive, + Other, +} + +pub enum ActualImplExpectedLifetimeKind { + Two, + Any, + Some, + Nothing, +} + +impl<'tcx> ActualImplExplNotes<'tcx> { + pub fn new_expected( + kind: ActualImplExpectedKind, + lt_kind: ActualImplExpectedLifetimeKind, + leading_ellipsis: bool, + ty_or_sig: TyOrSig<'tcx>, + trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>, + lifetime_1: usize, + lifetime_2: usize, + ) -> Self { + match (kind, lt_kind) { + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedSignatureTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedPassiveTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => { + Self::ExpectedOtherTwo { + leading_ellipsis, + ty_or_sig, + trait_path, + lifetime_1, + lifetime_2, + } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => { + Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => { + Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 } + } + (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => { + Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path } + } + } + } +} + +#[derive(Diagnostic)] +#[diag(trait_selection_trait_placeholder_mismatch)] +pub struct TraitPlaceholderMismatch<'tcx> { + #[primary_span] + pub span: Span, + #[label(trait_selection_label_satisfy)] + pub satisfy_span: Option<Span>, + #[label(trait_selection_label_where)] + pub where_span: Option<Span>, + #[label(trait_selection_label_dup)] + pub dup_span: Option<Span>, + pub def_id: String, + pub trait_def_id: String, + + #[subdiagnostic] + pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>, +} + +pub struct ConsiderBorrowingParamHelp { + pub spans: Vec<Span>, +} + +impl Subdiagnostic for ConsiderBorrowingParamHelp { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + let mut type_param_span: MultiSpan = self.spans.clone().into(); + for &span in &self.spans { + // Seems like we can't call f() here as Into<DiagMessage> is required + type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing); + } + let msg = f(diag, fluent::trait_selection_tid_param_help.into()); + diag.span_help(type_param_span, msg); + } +} + +#[derive(Subdiagnostic)] +#[help(trait_selection_tid_rel_help)] +pub struct RelationshipHelp; + +#[derive(Diagnostic)] +#[diag(trait_selection_trait_impl_diff)] +pub struct TraitImplDiff { + #[primary_span] + #[label(trait_selection_found)] + pub sp: Span, + #[label(trait_selection_expected)] + pub trait_sp: Span, + #[note(trait_selection_expected_found)] + pub note: (), + #[subdiagnostic] + pub param_help: ConsiderBorrowingParamHelp, + #[subdiagnostic] + // Seems like subdiagnostics are always pushed to the end, so this one + // also has to be a subdiagnostic to maintain order. + pub rel_help: Option<RelationshipHelp>, + pub expected: String, + pub found: String, +} + +pub struct DynTraitConstraintSuggestion { + pub span: Span, + pub ident: Ident, +} + +impl Subdiagnostic for DynTraitConstraintSuggestion { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + let mut multi_span: MultiSpan = vec![self.span].into(); + multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label); + multi_span + .push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement); + let msg = f(diag, fluent::trait_selection_dtcs_has_req_note.into()); + diag.span_note(multi_span, msg); + let msg = f(diag, fluent::trait_selection_dtcs_suggestion.into()); + diag.span_suggestion_verbose( + self.span.shrink_to_hi(), + msg, + " + '_", + Applicability::MaybeIncorrect, + ); + } +} + +#[derive(Diagnostic)] +#[diag(trait_selection_but_calling_introduces, code = E0772)] +pub struct ButCallingIntroduces { + #[label(trait_selection_label1)] + pub param_ty_span: Span, + #[primary_span] + #[label(trait_selection_label2)] + pub cause_span: Span, + + pub has_param_name: bool, + pub param_name: String, + pub has_lifetime: bool, + pub lifetime: String, + pub assoc_item: Symbol, + pub has_impl_path: bool, + pub impl_path: String, +} + +pub struct ReqIntroducedLocations { + pub span: MultiSpan, + pub spans: Vec<Span>, + pub fn_decl_span: Span, + pub cause_span: Span, + pub add_label: bool, +} + +impl Subdiagnostic for ReqIntroducedLocations { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + mut self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + for sp in self.spans { + self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here); + } + + if self.add_label { + self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by); + } + self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of); + let msg = f(diag, fluent::trait_selection_ril_static_introduced_by.into()); + diag.span_note(self.span, msg); + } +} + +pub struct MoreTargeted { + pub ident: Symbol, +} + +impl Subdiagnostic for MoreTargeted { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + diag.code(E0772); + diag.primary_message(fluent::trait_selection_more_targeted); + diag.arg("ident", self.ident); + } +} + +#[derive(Diagnostic)] +#[diag(trait_selection_but_needs_to_satisfy, code = E0759)] +pub struct ButNeedsToSatisfy { + #[primary_span] + pub sp: Span, + #[label(trait_selection_influencer)] + pub influencer_point: Span, + #[label(trait_selection_used_here)] + pub spans: Vec<Span>, + #[label(trait_selection_require)] + pub require_span_as_label: Option<Span>, + #[note(trait_selection_require)] + pub require_span_as_note: Option<Span>, + #[note(trait_selection_introduced_by_bound)] + pub bound: Option<Span>, + + #[subdiagnostic] + pub req_introduces_loc: Option<ReqIntroducedLocations>, + + pub has_param_name: bool, + pub param_name: String, + pub spans_empty: bool, + pub has_lifetime: bool, + pub lifetime: String, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_outlives_content, code = E0312)] +pub struct OutlivesContent<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub notes: Vec<note_and_explain::RegionExplanation<'a>>, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_outlives_bound, code = E0476)] +pub struct OutlivesBound<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub notes: Vec<note_and_explain::RegionExplanation<'a>>, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_fulfill_req_lifetime, code = E0477)] +pub struct FulfillReqLifetime<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, + #[subdiagnostic] + pub note: Option<note_and_explain::RegionExplanation<'a>>, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_lf_bound_not_satisfied, code = E0478)] +pub struct LfBoundNotSatisfied<'a> { + #[primary_span] + pub span: Span, + #[subdiagnostic] + pub notes: Vec<note_and_explain::RegionExplanation<'a>>, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_ref_longer_than_data, code = E0491)] +pub struct RefLongerThanData<'a> { + #[primary_span] + pub span: Span, + pub ty: Ty<'a>, + #[subdiagnostic] + pub notes: Vec<note_and_explain::RegionExplanation<'a>>, +} + +#[derive(Subdiagnostic)] +pub enum WhereClauseSuggestions { + #[suggestion( + trait_selection_where_remove, + code = "", + applicability = "machine-applicable", + style = "verbose" + )] + Remove { + #[primary_span] + span: Span, + }, + #[suggestion( + trait_selection_where_copy_predicates, + code = "{space}where {trait_predicates}", + applicability = "machine-applicable", + style = "verbose" + )] + CopyPredicates { + #[primary_span] + span: Span, + space: &'static str, + trait_predicates: String, + }, +} + +#[derive(Subdiagnostic)] +pub enum SuggestRemoveSemiOrReturnBinding { + #[multipart_suggestion( + trait_selection_srs_remove_and_box, + applicability = "machine-applicable" + )] + RemoveAndBox { + #[suggestion_part(code = "Box::new(")] + first_lo: Span, + #[suggestion_part(code = ")")] + first_hi: Span, + #[suggestion_part(code = "Box::new(")] + second_lo: Span, + #[suggestion_part(code = ")")] + second_hi: Span, + #[suggestion_part(code = "")] + sp: Span, + }, + #[suggestion( + trait_selection_srs_remove, + style = "short", + code = "", + applicability = "machine-applicable" + )] + Remove { + #[primary_span] + sp: Span, + }, + #[suggestion( + trait_selection_srs_add, + style = "verbose", + code = "{code}", + applicability = "maybe-incorrect" + )] + Add { + #[primary_span] + sp: Span, + code: String, + ident: Ident, + }, + #[note(trait_selection_srs_add_one)] + AddOne { + #[primary_span] + spans: MultiSpan, + }, +} + +#[derive(Subdiagnostic)] +pub enum ConsiderAddingAwait { + #[help(trait_selection_await_both_futures)] + BothFuturesHelp, + #[multipart_suggestion(trait_selection_await_both_futures, applicability = "maybe-incorrect")] + BothFuturesSugg { + #[suggestion_part(code = ".await")] + first: Span, + #[suggestion_part(code = ".await")] + second: Span, + }, + #[suggestion( + trait_selection_await_future, + code = ".await", + style = "verbose", + applicability = "maybe-incorrect" + )] + FutureSugg { + #[primary_span] + span: Span, + }, + #[note(trait_selection_await_note)] + FutureSuggNote { + #[primary_span] + span: Span, + }, + #[multipart_suggestion( + trait_selection_await_future, + style = "verbose", + applicability = "maybe-incorrect" + )] + FutureSuggMultiple { + #[suggestion_part(code = ".await")] + spans: Vec<Span>, + }, +} + +#[derive(Diagnostic)] +pub enum PlaceholderRelationLfNotSatisfied { + #[diag(trait_selection_lf_bound_not_satisfied)] + HasBoth { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_defined_with_sub)] + sub_span: Span, + #[note(trait_selection_prlf_must_outlive_with_sup)] + sup_span: Span, + sub_symbol: Symbol, + sup_symbol: Symbol, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, + #[diag(trait_selection_lf_bound_not_satisfied)] + HasSub { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_defined_with_sub)] + sub_span: Span, + #[note(trait_selection_prlf_must_outlive_without_sup)] + sup_span: Span, + sub_symbol: Symbol, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, + #[diag(trait_selection_lf_bound_not_satisfied)] + HasSup { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_defined_without_sub)] + sub_span: Span, + #[note(trait_selection_prlf_must_outlive_with_sup)] + sup_span: Span, + sup_symbol: Symbol, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, + #[diag(trait_selection_lf_bound_not_satisfied)] + HasNone { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_defined_without_sub)] + sub_span: Span, + #[note(trait_selection_prlf_must_outlive_without_sup)] + sup_span: Span, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, + #[diag(trait_selection_lf_bound_not_satisfied)] + OnlyPrimarySpan { + #[primary_span] + span: Span, + #[note(trait_selection_prlf_known_limitation)] + note: (), + }, +} + +#[derive(Diagnostic)] +#[diag(trait_selection_opaque_captures_lifetime, code = E0700)] +pub struct OpaqueCapturesLifetime<'tcx> { + #[primary_span] + pub span: Span, + #[label] + pub opaque_ty_span: Span, + pub opaque_ty: Ty<'tcx>, +} + +#[derive(Subdiagnostic)] +pub enum FunctionPointerSuggestion<'a> { + #[suggestion( + trait_selection_fps_use_ref, + code = "&{fn_name}", + style = "verbose", + applicability = "maybe-incorrect" + )] + UseRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + }, + #[suggestion( + trait_selection_fps_remove_ref, + code = "{fn_name}", + style = "verbose", + applicability = "maybe-incorrect" + )] + RemoveRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + }, + #[suggestion( + trait_selection_fps_cast, + code = "&({fn_name} as {sig})", + style = "verbose", + applicability = "maybe-incorrect" + )] + CastRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + sig: Binder<'a, FnSig<'a>>, + }, + #[suggestion( + trait_selection_fps_cast, + code = "{fn_name} as {sig}", + style = "verbose", + applicability = "maybe-incorrect" + )] + Cast { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + sig: Binder<'a, FnSig<'a>>, + }, + #[suggestion( + trait_selection_fps_cast_both, + code = "{fn_name} as {found_sig}", + style = "hidden", + applicability = "maybe-incorrect" + )] + CastBoth { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + found_sig: Binder<'a, FnSig<'a>>, + expected_sig: Binder<'a, FnSig<'a>>, + }, + #[suggestion( + trait_selection_fps_cast_both, + code = "&({fn_name} as {found_sig})", + style = "hidden", + applicability = "maybe-incorrect" + )] + CastBothRef { + #[primary_span] + span: Span, + #[skip_arg] + fn_name: String, + #[skip_arg] + found_sig: Binder<'a, FnSig<'a>>, + expected_sig: Binder<'a, FnSig<'a>>, + }, +} + +#[derive(Subdiagnostic)] +#[note(trait_selection_fps_items_are_distinct)] +pub struct FnItemsAreDistinct; + +#[derive(Subdiagnostic)] +#[note(trait_selection_fn_uniq_types)] +pub struct FnUniqTypes; + +#[derive(Subdiagnostic)] +#[help(trait_selection_fn_consider_casting)] +pub struct FnConsiderCasting { + pub casting: String, +} + +#[derive(Subdiagnostic)] +pub enum SuggestAccessingField<'a> { + #[suggestion( + trait_selection_suggest_accessing_field, + code = "{snippet}.{name}", + applicability = "maybe-incorrect" + )] + Safe { + #[primary_span] + span: Span, + snippet: String, + name: Symbol, + ty: Ty<'a>, + }, + #[suggestion( + trait_selection_suggest_accessing_field, + code = "unsafe {{ {snippet}.{name} }}", + applicability = "maybe-incorrect" + )] + Unsafe { + #[primary_span] + span: Span, + snippet: String, + name: Symbol, + ty: Ty<'a>, + }, +} + +#[derive(Subdiagnostic)] +#[multipart_suggestion(trait_selection_stp_wrap_one, applicability = "maybe-incorrect")] +pub struct SuggestTuplePatternOne { + pub variant: String, + #[suggestion_part(code = "{variant}(")] + pub span_low: Span, + #[suggestion_part(code = ")")] + pub span_high: Span, +} + +pub struct SuggestTuplePatternMany { + pub path: String, + pub cause_span: Span, + pub compatible_variants: Vec<String>, +} + +impl Subdiagnostic for SuggestTuplePatternMany { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + f: &F, + ) { + diag.arg("path", self.path); + let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into()); + diag.multipart_suggestions( + message, + self.compatible_variants.into_iter().map(|variant| { + vec![ + (self.cause_span.shrink_to_lo(), format!("{variant}(")), + (self.cause_span.shrink_to_hi(), ")".to_string()), + ] + }), + rustc_errors::Applicability::MaybeIncorrect, + ); + } +} + +#[derive(Subdiagnostic)] +pub enum TypeErrorAdditionalDiags { + #[suggestion( + trait_selection_meant_byte_literal, + code = "b'{code}'", + applicability = "machine-applicable" + )] + MeantByteLiteral { + #[primary_span] + span: Span, + code: String, + }, + #[suggestion( + trait_selection_meant_char_literal, + code = "'{code}'", + applicability = "machine-applicable" + )] + MeantCharLiteral { + #[primary_span] + span: Span, + code: String, + }, + #[multipart_suggestion( + trait_selection_meant_str_literal, + applicability = "machine-applicable" + )] + MeantStrLiteral { + #[suggestion_part(code = "\"")] + start: Span, + #[suggestion_part(code = "\"")] + end: Span, + }, + #[suggestion( + trait_selection_consider_specifying_length, + code = "{length}", + applicability = "maybe-incorrect" + )] + ConsiderSpecifyingLength { + #[primary_span] + span: Span, + length: u64, + }, + #[note(trait_selection_try_cannot_convert)] + TryCannotConvert { found: String, expected: String }, + #[suggestion( + trait_selection_tuple_trailing_comma, + code = ",", + applicability = "machine-applicable" + )] + TupleOnlyComma { + #[primary_span] + span: Span, + }, + #[multipart_suggestion( + trait_selection_tuple_trailing_comma, + applicability = "machine-applicable" + )] + TupleAlsoParentheses { + #[suggestion_part(code = "(")] + span_low: Span, + #[suggestion_part(code = ",)")] + span_high: Span, + }, + #[suggestion( + trait_selection_suggest_add_let_for_letchains, + style = "verbose", + applicability = "machine-applicable", + code = "let " + )] + AddLetForLetChains { + #[primary_span] + span: Span, + }, +} + +#[derive(Diagnostic)] +pub enum ObligationCauseFailureCode { + #[diag(trait_selection_oc_method_compat, code = E0308)] + MethodCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_type_compat, code = E0308)] + TypeCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_const_compat, code = E0308)] + ConstCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_try_compat, code = E0308)] + TryCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_match_compat, code = E0308)] + MatchCompat { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_if_else_different, code = E0308)] + IfElseDifferent { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_no_else, code = E0317)] + NoElse { + #[primary_span] + span: Span, + }, + #[diag(trait_selection_oc_no_diverge, code = E0308)] + NoDiverge { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_fn_main_correct_type, code = E0580)] + FnMainCorrectType { + #[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] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + lang_item_name: Symbol, + }, + #[diag(trait_selection_oc_intrinsic_correct_type, code = E0308)] + IntrinsicCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_method_correct_type, code = E0308)] + MethodCorrectType { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_closure_selfref, code = E0644)] + ClosureSelfref { + #[primary_span] + span: Span, + }, + #[diag(trait_selection_oc_cant_coerce, code = E0308)] + CantCoerce { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, + #[diag(trait_selection_oc_generic, code = E0308)] + Generic { + #[primary_span] + span: Span, + #[subdiagnostic] + subdiags: Vec<TypeErrorAdditionalDiags>, + }, +} + +#[derive(Subdiagnostic)] +pub enum AddPreciseCapturing { + #[suggestion( + trait_selection_precise_capturing_new, + style = "verbose", + code = " + use<{concatenated_bounds}>", + applicability = "machine-applicable" + )] + New { + #[primary_span] + span: Span, + new_lifetime: Symbol, + concatenated_bounds: String, + }, + #[suggestion( + trait_selection_precise_capturing_existing, + style = "verbose", + code = "{pre}{new_lifetime}{post}", + applicability = "machine-applicable" + )] + Existing { + #[primary_span] + span: Span, + new_lifetime: Symbol, + pre: &'static str, + post: &'static str, + }, +} + +pub struct AddPreciseCapturingAndParams { + pub suggs: Vec<(Span, String)>, + pub new_lifetime: Symbol, + pub apit_spans: Vec<Span>, +} + +impl Subdiagnostic for AddPreciseCapturingAndParams { + fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>( + self, + diag: &mut Diag<'_, G>, + _f: &F, + ) { + diag.arg("new_lifetime", self.new_lifetime); + diag.multipart_suggestion_verbose( + fluent::trait_selection_precise_capturing_new_but_apit, + self.suggs, + Applicability::MaybeIncorrect, + ); + diag.span_note(self.apit_spans, fluent::trait_selection_warn_removing_apit_params); + } +} diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs index d71b7f3c264..1f18cd8c8d8 100644 --- a/compiler/rustc_infer/src/errors/note_and_explain.rs +++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs @@ -173,7 +173,7 @@ impl Subdiagnostic for RegionExplanation<'_> { diag.arg("desc_kind", self.desc.kind); diag.arg("desc_arg", self.desc.arg); - let msg = f(diag, fluent::infer_region_explanation.into()); + let msg = f(diag, fluent::trait_selection_region_explanation.into()); if let Some(span) = self.desc.span { diag.span_note(span, msg); } else { diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index d0a12d73941..1bd66266936 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -22,11 +22,14 @@ #![feature(control_flow_enum)] #![feature(extract_if)] #![feature(if_let_guard)] +#![feature(iter_intersperse)] #![feature(let_chains)] #![feature(never_type)] #![feature(rustdoc_internals)] +#![feature(try_blocks)] #![feature(type_alias_impl_trait)] #![feature(unwrap_infallible)] +#![feature(yeet_expr)] #![recursion_limit = "512"] // For rustdoc // tidy-alphabetical-end diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs index ca313590265..ddaef7c159f 100644 --- a/compiler/rustc_trait_selection/src/solve/normalize.rs +++ b/compiler/rustc_trait_selection/src/solve/normalize.rs @@ -1,7 +1,8 @@ use std::fmt::Debug; use std::marker::PhantomData; -use crate::error_reporting::traits::{OverflowCause, TypeErrCtxtOverflowExt}; +use crate::error_reporting::traits::OverflowCause; +use crate::error_reporting::InferCtxtErrorExt; use crate::traits::query::evaluate_obligation::InferCtxtExt; use crate::traits::{BoundVarReplacer, PlaceholderReplacer, ScrubbedTraitError}; use rustc_data_structures::stack::ensure_sufficient_stack; diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index bdc27e734f9..49730b532a3 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -3,7 +3,7 @@ use std::fmt::Debug; use super::{FromSolverError, TraitEngine}; use super::{FulfillmentContext, ScrubbedTraitError}; -use crate::error_reporting::traits::TypeErrCtxtExt; +use crate::error_reporting::InferCtxtErrorExt; use crate::regions::InferCtxtRegionExt; use crate::solve::FulfillmentCtxt as NextFulfillmentCtxt; use crate::solve::NextSolverError; diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 5597c8be592..cc0bb7a60b2 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -1,4 +1,3 @@ -use crate::error_reporting::traits::TypeErrCtxtOverflowExt; use crate::infer::{InferCtxt, TyOrConstInferVar}; use crate::traits::normalize::normalize_with_depth_to; use rustc_data_structures::captures::Captures; @@ -25,6 +24,7 @@ use super::Unimplemented; use super::{const_evaluatable, ScrubbedTraitError}; use super::{FulfillmentError, FulfillmentErrorCode}; +use crate::error_reporting::InferCtxtErrorExt; use crate::traits::project::PolyProjectionObligation; use crate::traits::project::ProjectionCacheKeyExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt; diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index baec2268629..d749b686803 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -4,6 +4,7 @@ use crate::regions::InferCtxtRegionExt; use crate::traits::{self, FulfillmentError, ObligationCause}; use hir::LangItem; +use rustc_ast::Mutability; use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; use rustc_infer::infer::outlives::env::OutlivesEnvironment; @@ -19,6 +20,8 @@ pub enum CopyImplementationError<'tcx> { } pub enum ConstParamTyImplementationError<'tcx> { + UnsizedConstParamsFeatureRequired, + InvalidInnerTyOfBuiltinTy(Vec<(Ty<'tcx>, InfringingFieldsReason<'tcx>)>), InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), NotAnAdtOrBuiltinAllowed, } @@ -77,9 +80,9 @@ pub fn type_allowed_to_implement_copy<'tcx>( Ok(()) } -/// Checks that the fields of the type (an ADT) all implement `ConstParamTy`. +/// Checks that the fields of the type (an ADT) all implement `(Unsized?)ConstParamTy`. /// -/// If fields don't implement `ConstParamTy`, return an error containing a list of +/// If fields don't implement `(Unsized?)ConstParamTy`, return an error containing a list of /// those violating fields. /// /// If it's not an ADT, int ty, `bool` or `char`, returns `Err(NotAnAdtOrBuiltinAllowed)`. @@ -87,35 +90,95 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, + lang_item: LangItem, parent_cause: ObligationCause<'tcx>, ) -> Result<(), ConstParamTyImplementationError<'tcx>> { - let (adt, args) = match self_type.kind() { - // `core` provides these impls. - ty::Uint(_) - | ty::Int(_) - | ty::Bool - | ty::Char - | ty::Str - | ty::Array(..) - | ty::Slice(_) - | ty::Ref(.., hir::Mutability::Not) - | ty::Tuple(_) => return Ok(()), + assert!(matches!(lang_item, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy)); - &ty::Adt(adt, args) => (adt, args), + let inner_tys: Vec<_> = match *self_type.kind() { + // Trivially okay as these types are all: + // - Sized + // - Contain no nested types + // - Have structural equality + ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => return Ok(()), + + // Handle types gated under `feature(unsized_const_params)` + // FIXME(unsized_const_params): Make `const N: [u8]` work then forbid references + ty::Slice(inner_ty) | ty::Ref(_, inner_ty, Mutability::Not) + if lang_item == LangItem::UnsizedConstParamTy => + { + vec![inner_ty] + } + ty::Str if lang_item == LangItem::UnsizedConstParamTy => { + vec![Ty::new_slice(tcx, tcx.types.u8)] + } + ty::Str | ty::Slice(..) | ty::Ref(_, _, Mutability::Not) => { + return Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired); + } + + ty::Array(inner_ty, _) => vec![inner_ty], + + // `str` morally acts like a newtype around `[u8]` + ty::Tuple(inner_tys) => inner_tys.into_iter().collect(), + + ty::Adt(adt, args) if adt.is_enum() || adt.is_struct() => { + all_fields_implement_trait( + tcx, + param_env, + self_type, + adt, + args, + parent_cause.clone(), + lang_item, + ) + .map_err(ConstParamTyImplementationError::InfrigingFields)?; + + vec![] + } _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed), }; - all_fields_implement_trait( - tcx, - param_env, - self_type, - adt, - args, - parent_cause, - hir::LangItem::ConstParamTy, - ) - .map_err(ConstParamTyImplementationError::InfrigingFields)?; + let mut infringing_inner_tys = vec![]; + for inner_ty in inner_tys { + // We use an ocx per inner ty for better diagnostics + let infcx = tcx.infer_ctxt().build(); + let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); + + ocx.register_bound( + parent_cause.clone(), + param_env, + inner_ty, + tcx.require_lang_item(lang_item, Some(parent_cause.span)), + ); + + let errors = ocx.select_all_or_error(); + if !errors.is_empty() { + infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Fulfill(errors))); + continue; + } + + // Check regions assuming the self type of the impl is WF + let outlives_env = OutlivesEnvironment::with_bounds( + param_env, + infcx.implied_bounds_tys( + param_env, + parent_cause.body_id, + &FxIndexSet::from_iter([self_type]), + ), + ); + let errors = infcx.resolve_regions(&outlives_env); + if !errors.is_empty() { + infringing_inner_tys.push((inner_ty, InfringingFieldsReason::Regions(errors))); + continue; + } + } + + if !infringing_inner_tys.is_empty() { + return Err(ConstParamTyImplementationError::InvalidInnerTyOfBuiltinTy( + infringing_inner_tys, + )); + } Ok(()) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index f7eb1730582..c57ca014799 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -22,7 +22,7 @@ mod util; pub mod vtable; pub mod wf; -use crate::error_reporting::traits::TypeErrCtxtExt as _; +use crate::error_reporting::InferCtxtErrorExt; use crate::infer::outlives::env::OutlivesEnvironment; use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::regions::InferCtxtRegionExt; diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 01ba8c02ea6..26cb9bb5a3d 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -3,7 +3,7 @@ use super::SelectionContext; use super::{project, with_replaced_escaping_bound_vars, BoundVarReplacer, PlaceholderReplacer}; use crate::error_reporting::traits::OverflowCause; -use crate::error_reporting::traits::TypeErrCtxtOverflowExt; +use crate::error_reporting::InferCtxtErrorExt; use crate::solve::NextSolverError; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_infer::infer::at::At; diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index c11e86abef8..75f1af7fcf5 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -3,7 +3,7 @@ //! `normalize_canonicalized_projection_ty` query when it encounters projections. use crate::error_reporting::traits::OverflowCause; -use crate::error_reporting::traits::TypeErrCtxtOverflowExt; +use crate::error_reporting::InferCtxtErrorExt; use crate::infer::at::At; use crate::infer::canonical::OriginalQueryValues; use crate::infer::{InferCtxt, InferOk}; diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 7a93f59f163..d6590322caa 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -18,7 +18,7 @@ use super::{ TraitQueryMode, }; -use crate::error_reporting::traits::TypeErrCtxtOverflowExt; +use crate::error_reporting::InferCtxtErrorExt; use crate::infer::{InferCtxt, InferCtxtExt, InferOk, TypeFreshener}; use crate::solve::InferCtxtSelectExt as _; use crate::traits::normalize::normalize_with_depth; diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 3ee5fd876ff..ada2c8e81de 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -7,7 +7,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::bug; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{ ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext, Unimplemented, diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 2d70fdc3935..06cd6389efc 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -2,7 +2,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; -use rustc_trait_selection::error_reporting::traits::TypeErrCtxtOverflowExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{ normalize::NormalizationResult, CanonicalAliasGoal, NoSolution, diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index f299aa0124d..405430377e5 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -704,7 +704,7 @@ impl<T> Box<[T]> { } /// Constructs a new boxed slice with uninitialized contents. Returns an error if - /// the allocation fails + /// the allocation fails. /// /// # Examples /// @@ -739,7 +739,7 @@ impl<T> Box<[T]> { } /// Constructs a new boxed slice with uninitialized contents, with the memory - /// being filled with `0` bytes. Returns an error if the allocation fails + /// being filled with `0` bytes. Returns an error if the allocation fails. /// /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage /// of this method. @@ -831,6 +831,85 @@ impl<T, A: Allocator> Box<[T], A> { pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> { unsafe { RawVec::with_capacity_zeroed_in(len, alloc).into_box(len) } } + + /// Constructs a new boxed slice with uninitialized contents in the provided allocator. Returns an error if + /// the allocation fails. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let mut values = Box::<[u32], _>::try_new_uninit_slice_in(3, System)?; + /// let values = unsafe { + /// // Deferred initialization: + /// values[0].as_mut_ptr().write(1); + /// values[1].as_mut_ptr().write(2); + /// values[2].as_mut_ptr().write(3); + /// values.assume_init() + /// }; + /// + /// assert_eq!(*values, [1, 2, 3]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn try_new_uninit_slice_in( + len: usize, + alloc: A, + ) -> Result<Box<[mem::MaybeUninit<T>], A>, AllocError> { + let ptr = if T::IS_ZST || len == 0 { + NonNull::dangling() + } else { + let layout = match Layout::array::<mem::MaybeUninit<T>>(len) { + Ok(l) => l, + Err(_) => return Err(AllocError), + }; + alloc.allocate(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) } + } + + /// Constructs a new boxed slice with uninitialized contents in the provided allocator, with the memory + /// being filled with `0` bytes. Returns an error if the allocation fails. + /// + /// See [`MaybeUninit::zeroed`][zeroed] for examples of correct and incorrect usage + /// of this method. + /// + /// # Examples + /// + /// ``` + /// #![feature(allocator_api, new_uninit)] + /// + /// use std::alloc::System; + /// + /// let values = Box::<[u32], _>::try_new_zeroed_slice_in(3, System)?; + /// let values = unsafe { values.assume_init() }; + /// + /// assert_eq!(*values, [0, 0, 0]); + /// # Ok::<(), std::alloc::AllocError>(()) + /// ``` + /// + /// [zeroed]: mem::MaybeUninit::zeroed + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] + pub fn try_new_zeroed_slice_in( + len: usize, + alloc: A, + ) -> Result<Box<[mem::MaybeUninit<T>], A>, AllocError> { + let ptr = if T::IS_ZST || len == 0 { + NonNull::dangling() + } else { + let layout = match Layout::array::<mem::MaybeUninit<T>>(len) { + Ok(l) => l, + Err(_) => return Err(AllocError), + }; + alloc.allocate_zeroed(layout)?.cast() + }; + unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) } + } } impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> { diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 49f89e70255..0ec46412e95 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -165,6 +165,7 @@ #![feature(const_unsafecell_get_mut)] #![feature(const_waker)] #![feature(coverage_attribute)] +#![feature(do_not_recommend)] #![feature(duration_consts_float)] #![feature(internal_impls_macro)] #![feature(ip)] @@ -248,6 +249,7 @@ #![feature(transparent_unions)] #![feature(try_blocks)] #![feature(unboxed_closures)] +#![feature(unsized_const_params)] #![feature(unsized_fn_params)] #![feature(with_negative_coherence)] // tidy-alphabetical-end diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 21abd7c036b..a87528033c0 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -975,31 +975,73 @@ pub trait PointerLike {} /// that all fields are also `ConstParamTy`, which implies that recursively, all fields /// are `StructuralPartialEq`. #[lang = "const_param_ty"] -#[unstable(feature = "adt_const_params", issue = "95174")] +#[unstable(feature = "unsized_const_params", issue = "95174")] #[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] #[allow(multiple_supertrait_upcastable)] -pub trait ConstParamTy: StructuralPartialEq + Eq {} +// We name this differently than the derive macro so that the `adt_const_params` can +// be used independently of `unsized_const_params` without requiring a full path +// to the derive macro every time it is used. This should be renamed on stabilization. +pub trait ConstParamTy_: UnsizedConstParamTy + StructuralPartialEq + Eq {} /// Derive macro generating an impl of the trait `ConstParamTy`. #[rustc_builtin_macro] +#[allow_internal_unstable(unsized_const_params)] #[unstable(feature = "adt_const_params", issue = "95174")] pub macro ConstParamTy($item:item) { /* compiler built-in */ } +#[cfg_attr(not(bootstrap), lang = "unsized_const_param_ty")] +#[unstable(feature = "unsized_const_params", issue = "95174")] +#[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] +/// A marker for types which can be used as types of `const` generic parameters. +/// +/// Equivalent to [`ConstParamTy_`] except that this is used by +/// the `unsized_const_params` to allow for fake unstable impls. +pub trait UnsizedConstParamTy: StructuralPartialEq + Eq {} + +/// Derive macro generating an impl of the trait `ConstParamTy`. +#[cfg(not(bootstrap))] +#[cfg_attr(not(bootstrap), rustc_builtin_macro)] +#[cfg_attr(not(bootstrap), allow_internal_unstable(unsized_const_params))] +#[cfg_attr(not(bootstrap), unstable(feature = "unsized_const_params", issue = "95174"))] +pub macro UnsizedConstParamTy($item:item) { + /* compiler built-in */ +} + // FIXME(adt_const_params): handle `ty::FnDef`/`ty::Closure` marker_impls! { #[unstable(feature = "adt_const_params", issue = "95174")] - ConstParamTy for + ConstParamTy_ for + usize, u8, u16, u32, u64, u128, + isize, i8, i16, i32, i64, i128, + bool, + char, + (), + {T: ConstParamTy_, const N: usize} [T; N], +} +#[cfg(bootstrap)] +marker_impls! { + #[unstable(feature = "adt_const_params", issue = "95174")] + ConstParamTy_ for + str, + {T: ConstParamTy_} [T], + {T: ConstParamTy_ + ?Sized} &T, +} + +marker_impls! { + #[unstable(feature = "unsized_const_params", issue = "95174")] + UnsizedConstParamTy for usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, bool, char, - str /* Technically requires `[u8]: ConstParamTy` */, (), - {T: ConstParamTy, const N: usize} [T; N], - {T: ConstParamTy} [T], - {T: ?Sized + ConstParamTy} &T, + {T: UnsizedConstParamTy, const N: usize} [T; N], + + str, + {T: UnsizedConstParamTy} [T], + {T: UnsizedConstParamTy + ?Sized} &T, } /// A common trait implemented by all function pointers. diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 827426b2358..ea73c5b80ba 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -1,4 +1,4 @@ -use crate::marker::ConstParamTy; +use crate::marker::{ConstParamTy_, UnsizedConstParamTy}; /// Are values of a type transmutable into values of another type? /// @@ -39,7 +39,9 @@ pub struct Assume { } #[unstable(feature = "transmutability", issue = "99571")] -impl ConstParamTy for Assume {} +impl ConstParamTy_ for Assume {} +#[unstable(feature = "transmutability", issue = "99571")] +impl UnsizedConstParamTy for Assume {} impl Assume { /// Do not assume that *you* have ensured any safety properties are met. diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 1a8fe1e6051..d93cb8d10e6 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -2507,6 +2507,7 @@ impl<T> ops::FromResidual for Option<T> { } } +#[diagnostic::do_not_recommend] #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] impl<T> ops::FromResidual<ops::Yeet<()>> for Option<T> { #[inline] diff --git a/library/core/src/result.rs b/library/core/src/result.rs index f8cdcc000c5..7f278296b7b 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1990,7 +1990,7 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Res } } } - +#[diagnostic::do_not_recommend] #[unstable(feature = "try_trait_v2_yeet", issue = "96374")] impl<T, E, F: From<E>> ops::FromResidual<ops::Yeet<E>> for Result<T, F> { #[inline] diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 8e961d8adc3..bc376b13f64 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,8 +1,9 @@ // See core/src/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; -use crate::marker::ConstParamTy; +use crate::marker::ConstParamTy_; use crate::marker::StructuralPartialEq; +use crate::marker::UnsizedConstParamTy; // Recursive macro for implementing n-ary tuple functions and operations // @@ -49,8 +50,15 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ - #[unstable(feature = "structural_match", issue = "31434")] - impl<$($T: ConstParamTy),+> ConstParamTy for ($($T,)+) + #[unstable(feature = "adt_const_params", issue = "95174")] + impl<$($T: ConstParamTy_),+> ConstParamTy_ for ($($T,)+) + {} + } + + maybe_tuple_doc! { + $($T)+ @ + #[unstable(feature = "unsized_const_params", issue = "95174")] + impl<$($T: UnsizedConstParamTy),+> UnsizedConstParamTy for ($($T,)+) {} } diff --git a/library/std/src/os/horizon/mod.rs b/library/std/src/os/horizon/mod.rs index 326d0ae9cb9..14ce409f42c 100644 --- a/library/std/src/os/horizon/mod.rs +++ b/library/std/src/os/horizon/mod.rs @@ -1,5 +1,6 @@ //! Definitions for Horizon OS +#![forbid(unsafe_op_in_unsafe_fn)] #![stable(feature = "raw_ext", since = "1.1.0")] pub mod fs; diff --git a/library/std/src/os/horizon/raw.rs b/library/std/src/os/horizon/raw.rs index 929fa7db1f9..e5368ea265a 100644 --- a/library/std/src/os/horizon/raw.rs +++ b/library/std/src/os/horizon/raw.rs @@ -38,6 +38,7 @@ pub type time_t = libc::time_t; #[repr(C)] #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] +#[allow(dead_code)] // This exists for parity with other `raw` modules, but isn't actually used. pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] pub st_dev: dev_t, diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs index 19b4fe22093..e75bcf74e5c 100644 --- a/library/std/src/os/solid/io.rs +++ b/library/std/src/os/solid/io.rs @@ -44,7 +44,6 @@ //! //! [`BorrowedFd<'a>`]: crate::os::solid::io::BorrowedFd -#![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "solid_ext", issue = "none")] use crate::fmt; diff --git a/library/std/src/os/solid/mod.rs b/library/std/src/os/solid/mod.rs index 0bb83c73ddf..75824048e24 100644 --- a/library/std/src/os/solid/mod.rs +++ b/library/std/src/os/solid/mod.rs @@ -1,4 +1,5 @@ #![stable(feature = "rust1", since = "1.0.0")] +#![forbid(unsafe_op_in_unsafe_fn)] pub mod ffi; pub mod io; diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs index 9a7741ddda7..0b158fb63df 100644 --- a/library/std/src/sys/pal/solid/mod.rs +++ b/library/std/src/sys/pal/solid/mod.rs @@ -1,6 +1,6 @@ #![allow(dead_code)] #![allow(missing_docs, nonstandard_style)] -#![deny(unsafe_op_in_unsafe_fn)] +#![forbid(unsafe_op_in_unsafe_fn)] pub mod abi; diff --git a/library/std/src/sys/pal/unix/alloc.rs b/library/std/src/sys/pal/unix/alloc.rs index eb3a57c212b..625ba5247f1 100644 --- a/library/std/src/sys/pal/unix/alloc.rs +++ b/library/std/src/sys/pal/unix/alloc.rs @@ -67,7 +67,7 @@ cfg_if::cfg_if! { ))] { #[inline] unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - libc::memalign(layout.align(), layout.size()) as *mut u8 + unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 } } } else { #[inline] diff --git a/library/std/src/sys/pal/unix/net.rs b/library/std/src/sys/pal/unix/net.rs index b8dc1538a63..bedb06043a7 100644 --- a/library/std/src/sys/pal/unix/net.rs +++ b/library/std/src/sys/pal/unix/net.rs @@ -4,7 +4,6 @@ use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut}; use crate::mem; use crate::net::{Shutdown, SocketAddr}; use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd}; -use crate::str; use crate::sys::fd::FileDesc; use crate::sys::pal::unix::IsMinusOne; use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; @@ -47,7 +46,9 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { #[cfg(not(target_os = "espidf"))] let detail = unsafe { - str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned() + // We can't always expect a UTF-8 environment. When we don't get that luxury, + // it's better to give a low-quality error message than none at all. + CStr::from_ptr(libc::gai_strerror(err)).to_string_lossy() }; #[cfg(target_os = "espidf")] diff --git a/library/std/src/sys/pal/unix/process/process_unsupported.rs b/library/std/src/sys/pal/unix/process/process_unsupported.rs index 33d359d3f84..90d53464c83 100644 --- a/library/std/src/sys/pal/unix/process/process_unsupported.rs +++ b/library/std/src/sys/pal/unix/process/process_unsupported.rs @@ -1,4 +1,3 @@ -use crate::fmt; use crate::io; use crate::num::NonZero; use crate::sys::pal::unix::unsupported::*; diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 0db08c1a926..6eeec48bf5e 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -87,13 +87,18 @@ mod imp { // out many large systems and all implementations allow returning from a // signal handler to work. For a more detailed explanation see the // comments on #26458. + /// SIGSEGV/SIGBUS entry point + /// # Safety + /// Rust doesn't call this, it *gets called*. + #[forbid(unsafe_op_in_unsafe_fn)] unsafe extern "C" fn signal_handler( signum: libc::c_int, info: *mut libc::siginfo_t, _data: *mut libc::c_void, ) { let (start, end) = GUARD.get(); - let addr = (*info).si_addr() as usize; + // SAFETY: this pointer is provided by the system and will always point to a valid `siginfo_t`. + let addr = unsafe { (*info).si_addr().addr() }; // If the faulting address is within the guard page, then we print a // message saying so and abort. @@ -105,9 +110,11 @@ mod imp { rtabort!("stack overflow"); } else { // Unregister ourselves by reverting back to the default behavior. - let mut action: sigaction = mem::zeroed(); + // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" + let mut action: sigaction = unsafe { mem::zeroed() }; action.sa_sigaction = SIG_DFL; - sigaction(signum, &action, ptr::null_mut()); + // SAFETY: pray this is a well-behaved POSIX implementation of fn sigaction + unsafe { sigaction(signum, &action, ptr::null_mut()) }; // See comment above for why this function returns. } @@ -117,32 +124,45 @@ mod imp { static MAIN_ALTSTACK: AtomicPtr<libc::c_void> = AtomicPtr::new(ptr::null_mut()); static NEED_ALTSTACK: AtomicBool = AtomicBool::new(false); + /// # Safety + /// Must be called only once + #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn init() { PAGE_SIZE.store(os::page_size(), Ordering::Relaxed); // Always write to GUARD to ensure the TLS variable is allocated. - let guard = install_main_guard().unwrap_or(0..0); + let guard = unsafe { install_main_guard().unwrap_or(0..0) }; GUARD.set((guard.start, guard.end)); - let mut action: sigaction = mem::zeroed(); + // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" + let mut action: sigaction = unsafe { mem::zeroed() }; for &signal in &[SIGSEGV, SIGBUS] { - sigaction(signal, ptr::null_mut(), &mut action); + // SAFETY: just fetches the current signal handler into action + unsafe { sigaction(signal, ptr::null_mut(), &mut action) }; // Configure our signal handler if one is not already set. if action.sa_sigaction == SIG_DFL { + if !NEED_ALTSTACK.load(Ordering::Relaxed) { + // haven't set up our sigaltstack yet + NEED_ALTSTACK.store(true, Ordering::Release); + let handler = unsafe { make_handler(true) }; + MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed); + mem::forget(handler); + } action.sa_flags = SA_SIGINFO | SA_ONSTACK; action.sa_sigaction = signal_handler as sighandler_t; - sigaction(signal, &action, ptr::null_mut()); - NEED_ALTSTACK.store(true, Ordering::Relaxed); + // SAFETY: only overriding signals if the default is set + unsafe { sigaction(signal, &action, ptr::null_mut()) }; } } - - let handler = make_handler(true); - MAIN_ALTSTACK.store(handler.data, Ordering::Relaxed); - mem::forget(handler); } + /// # Safety + /// Must be called only once + #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn cleanup() { - drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)); + // FIXME: I probably cause more bugs than I'm worth! + // see https://github.com/rust-lang/rust/issues/111272 + unsafe { drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)) }; } unsafe fn get_stack() -> libc::stack_t { @@ -187,34 +207,48 @@ mod imp { libc::stack_t { ss_sp: stackp, ss_flags: 0, ss_size: sigstack_size } } + /// # Safety + /// Mutates the alternate signal stack + #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn make_handler(main_thread: bool) -> Handler { - if !NEED_ALTSTACK.load(Ordering::Relaxed) { + if !NEED_ALTSTACK.load(Ordering::Acquire) { return Handler::null(); } if !main_thread { // Always write to GUARD to ensure the TLS variable is allocated. - let guard = current_guard().unwrap_or(0..0); + let guard = unsafe { current_guard() }.unwrap_or(0..0); GUARD.set((guard.start, guard.end)); } - let mut stack = mem::zeroed(); - sigaltstack(ptr::null(), &mut stack); + // SAFETY: assuming stack_t is zero-initializable + let mut stack = unsafe { mem::zeroed() }; + // SAFETY: reads current stack_t into stack + unsafe { sigaltstack(ptr::null(), &mut stack) }; // Configure alternate signal stack, if one is not already set. if stack.ss_flags & SS_DISABLE != 0 { - stack = get_stack(); - sigaltstack(&stack, ptr::null_mut()); + // SAFETY: We warned our caller this would happen! + unsafe { + stack = get_stack(); + sigaltstack(&stack, ptr::null_mut()); + } Handler { data: stack.ss_sp as *mut libc::c_void } } else { Handler::null() } } + /// # Safety + /// Must be called + /// - only with our handler or nullptr + /// - only when done with our altstack + /// This disables the alternate signal stack! + #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn drop_handler(data: *mut libc::c_void) { if !data.is_null() { let sigstack_size = sigstack_size(); let page_size = PAGE_SIZE.load(Ordering::Relaxed); - let stack = libc::stack_t { + let disabling_stack = libc::stack_t { ss_sp: ptr::null_mut(), ss_flags: SS_DISABLE, // Workaround for bug in macOS implementation of sigaltstack @@ -223,10 +257,11 @@ mod imp { // both ss_sp and ss_size should be ignored in this case. ss_size: sigstack_size, }; - sigaltstack(&stack, ptr::null_mut()); - // We know from `get_stackp` that the alternate stack we installed is part of a mapping - // that started one page earlier, so walk back a page and unmap from there. - munmap(data.sub(page_size), sigstack_size + page_size); + // SAFETY: we warned the caller this disables the alternate signal stack! + unsafe { sigaltstack(&disabling_stack, ptr::null_mut()) }; + // SAFETY: We know from `get_stackp` that the alternate stack we installed is part of + // a mapping that started one page earlier, so walk back a page and unmap from there. + unsafe { munmap(data.sub(page_size), sigstack_size + page_size) }; } } @@ -455,6 +490,7 @@ mod imp { } #[cfg(any(target_os = "macos", target_os = "openbsd", target_os = "solaris"))] + // FIXME: I am probably not unsafe. unsafe fn current_guard() -> Option<Range<usize>> { let stackptr = get_stack_start()?; let stackaddr = stackptr.addr(); @@ -469,6 +505,7 @@ mod imp { target_os = "netbsd", target_os = "l4re" ))] + // FIXME: I am probably not unsafe. unsafe fn current_guard() -> Option<Range<usize>> { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 296d19a926d..84f3d6a5399 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -8,7 +8,7 @@ use crate::ffi::CStr; use crate::mem; -use crate::os::raw::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void}; +use crate::os::raw::{c_uint, c_ulong, c_ushort, c_void}; use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; @@ -19,12 +19,6 @@ pub use windows_sys::*; pub type WCHAR = u16; -pub type socklen_t = c_int; -pub type ADDRESS_FAMILY = c_ushort; -pub use FD_SET as fd_set; -pub use LINGER as linger; -pub use TIMEVAL as timeval; - pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i32 as _); // https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170 @@ -42,20 +36,6 @@ pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() }; pub const OBJ_DONT_REPARSE: u32 = windows_sys::OBJ_DONT_REPARSE as u32; pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: u32 = windows_sys::FRS_ERR_SYSVOL_POPULATE_TIMEOUT as u32; -pub const AF_INET: c_int = windows_sys::AF_INET as c_int; -pub const AF_INET6: c_int = windows_sys::AF_INET6 as c_int; - -#[repr(C)] -pub struct ip_mreq { - pub imr_multiaddr: in_addr, - pub imr_interface: in_addr, -} - -#[repr(C)] -pub struct ipv6_mreq { - pub ipv6mr_multiaddr: in6_addr, - pub ipv6mr_interface: c_uint, -} // Equivalent to the `NT_SUCCESS` C preprocessor macro. // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values @@ -127,45 +107,6 @@ pub struct MOUNT_POINT_REPARSE_BUFFER { pub PathBuffer: WCHAR, } -#[repr(C)] -pub struct SOCKADDR_STORAGE_LH { - pub ss_family: ADDRESS_FAMILY, - pub __ss_pad1: [c_char; 6], - pub __ss_align: i64, - pub __ss_pad2: [c_char; 112], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in { - pub sin_family: ADDRESS_FAMILY, - pub sin_port: c_ushort, - pub sin_addr: in_addr, - pub sin_zero: [c_char; 8], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in6 { - pub sin6_family: ADDRESS_FAMILY, - pub sin6_port: c_ushort, - pub sin6_flowinfo: c_ulong, - pub sin6_addr: in6_addr, - pub sin6_scope_id: c_ulong, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in_addr { - pub s_addr: u32, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in6_addr { - pub s6_addr: [u8; 16], -} - // Desktop specific functions & types cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { @@ -205,42 +146,6 @@ pub unsafe extern "system" fn ReadFileEx( ) } -// POSIX compatibility shims. -pub unsafe fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int { - windows_sys::recv(socket, buf.cast::<u8>(), len, flags) -} -pub unsafe fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int { - windows_sys::send(socket, buf.cast::<u8>(), len, flags) -} -pub unsafe fn recvfrom( - socket: SOCKET, - buf: *mut c_void, - len: c_int, - flags: c_int, - addr: *mut SOCKADDR, - addrlen: *mut c_int, -) -> c_int { - windows_sys::recvfrom(socket, buf.cast::<u8>(), len, flags, addr, addrlen) -} -pub unsafe fn sendto( - socket: SOCKET, - buf: *const c_void, - len: c_int, - flags: c_int, - addr: *const SOCKADDR, - addrlen: c_int, -) -> c_int { - windows_sys::sendto(socket, buf.cast::<u8>(), len, flags, addr, addrlen) -} -pub unsafe fn getaddrinfo( - node: *const c_char, - service: *const c_char, - hints: *const ADDRINFOA, - res: *mut *mut ADDRINFOA, -) -> c_int { - windows_sys::getaddrinfo(node.cast::<u8>(), service.cast::<u8>(), hints, res) -} - cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { pub unsafe fn NtReadFile( diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 5ad4a3731d8..794e2c90c52 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2059,6 +2059,7 @@ Windows.Win32.Networking.WinSock.SOCK_RDM Windows.Win32.Networking.WinSock.SOCK_SEQPACKET Windows.Win32.Networking.WinSock.SOCK_STREAM Windows.Win32.Networking.WinSock.SOCKADDR +Windows.Win32.Networking.WinSock.SOCKADDR_STORAGE Windows.Win32.Networking.WinSock.SOCKADDR_UN Windows.Win32.Networking.WinSock.SOCKET Windows.Win32.Networking.WinSock.SOCKET_ERROR diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index fea00fec9ae..eae0f775860 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -2890,6 +2890,14 @@ pub struct SOCKADDR { } #[repr(C)] #[derive(Clone, Copy)] +pub struct SOCKADDR_STORAGE { + pub ss_family: ADDRESS_FAMILY, + pub __ss_pad1: [i8; 6], + pub __ss_align: i64, + pub __ss_pad2: [i8; 112], +} +#[repr(C)] +#[derive(Clone, Copy)] pub struct SOCKADDR_UN { pub sun_family: ADDRESS_FAMILY, pub sun_path: [i8; 108], diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index d51fb56238f..b7ecff032e4 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -17,14 +17,100 @@ use crate::time::Duration; use core::ffi::{c_int, c_long, c_ulong, c_ushort}; +#[allow(non_camel_case_types)] pub type wrlen_t = i32; pub mod netc { - pub use crate::sys::c::ADDRESS_FAMILY as sa_family_t; - pub use crate::sys::c::ADDRINFOA as addrinfo; - pub use crate::sys::c::SOCKADDR as sockaddr; - pub use crate::sys::c::SOCKADDR_STORAGE_LH as sockaddr_storage; - pub use crate::sys::c::*; + //! BSD socket compatibility shim + //! + //! Some Windows API types are not quite what's expected by our cross-platform + //! net code. E.g. naming differences or different pointer types. + use crate::sys::c::{self, ADDRESS_FAMILY, ADDRINFOA, SOCKADDR, SOCKET}; + use core::ffi::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void}; + + // re-exports from Windows API bindings. + pub use crate::sys::c::{ + bind, connect, freeaddrinfo, getpeername, getsockname, getsockopt, listen, setsockopt, + ADDRESS_FAMILY as sa_family_t, ADDRINFOA as addrinfo, IPPROTO_IP, IPPROTO_IPV6, + IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY, + IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, + SOCKADDR as sockaddr, SOCKADDR_STORAGE as sockaddr_storage, SOCK_DGRAM, SOCK_STREAM, + SOL_SOCKET, SO_BROADCAST, SO_RCVTIMEO, SO_SNDTIMEO, + }; + + #[allow(non_camel_case_types)] + pub type socklen_t = c_int; + + pub const AF_INET: i32 = c::AF_INET as i32; + pub const AF_INET6: i32 = c::AF_INET6 as i32; + + // The following two structs use a union in the generated bindings but + // our cross-platform code expects a normal field so it's redefined here. + // As a consequence, we also need to redefine other structs that use this struct. + #[repr(C)] + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[repr(C)] + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + #[repr(C)] + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: ADDRESS_FAMILY, + pub sin_port: c_ushort, + pub sin_addr: in_addr, + pub sin_zero: [c_char; 8], + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: ADDRESS_FAMILY, + pub sin6_port: c_ushort, + pub sin6_flowinfo: c_ulong, + pub sin6_addr: in6_addr, + pub sin6_scope_id: c_ulong, + } + + pub unsafe fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int { + unsafe { c::send(socket, buf.cast::<u8>(), len, flags) } + } + pub unsafe fn sendto( + socket: SOCKET, + buf: *const c_void, + len: c_int, + flags: c_int, + addr: *const SOCKADDR, + addrlen: c_int, + ) -> c_int { + unsafe { c::sendto(socket, buf.cast::<u8>(), len, flags, addr, addrlen) } + } + pub unsafe fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const ADDRINFOA, + res: *mut *mut ADDRINFOA, + ) -> c_int { + unsafe { c::getaddrinfo(node.cast::<u8>(), service.cast::<u8>(), hints, res) } + } } pub struct Socket(OwnedSocket); @@ -102,8 +188,8 @@ where impl Socket { pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> { let family = match *addr { - SocketAddr::V4(..) => c::AF_INET, - SocketAddr::V6(..) => c::AF_INET6, + SocketAddr::V4(..) => netc::AF_INET, + SocketAddr::V6(..) => netc::AF_INET6, }; let socket = unsafe { c::WSASocketW( @@ -157,7 +243,7 @@ impl Socket { return Err(io::Error::ZERO_TIMEOUT); } - let mut timeout = c::timeval { + let mut timeout = c::TIMEVAL { tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, tv_usec: timeout.subsec_micros() as c_long, }; @@ -167,7 +253,7 @@ impl Socket { } let fds = { - let mut fds = unsafe { mem::zeroed::<c::fd_set>() }; + let mut fds = unsafe { mem::zeroed::<c::FD_SET>() }; fds.fd_count = 1; fds.fd_array[0] = self.as_raw(); fds @@ -295,8 +381,8 @@ impl Socket { buf: &mut [u8], flags: c_int, ) -> io::Result<(usize, SocketAddr)> { - let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE_LH>() }; - let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; + let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE>() }; + let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; let length = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; // On unix when a socket is shut down all further reads return 0, so we @@ -399,7 +485,7 @@ impl Socket { } pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> { - let linger = c::linger { + let linger = c::LINGER { l_onoff: linger.is_some() as c_ushort, l_linger: linger.unwrap_or_default().as_secs() as c_ushort, }; @@ -408,7 +494,7 @@ impl Socket { } pub fn linger(&self) -> io::Result<Option<Duration>> { - let val: c::linger = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; + let val: c::LINGER = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } diff --git a/library/std/src/sys/path/unsupported_backslash.rs b/library/std/src/sys/path/unsupported_backslash.rs index 7045c9be25b..855f443678c 100644 --- a/library/std/src/sys/path/unsupported_backslash.rs +++ b/library/std/src/sys/path/unsupported_backslash.rs @@ -1,3 +1,4 @@ +#![forbid(unsafe_op_in_unsafe_fn)] use crate::ffi::OsStr; use crate::io; use crate::path::{Path, PathBuf, Prefix}; diff --git a/library/std/src/sys/sync/mutex/itron.rs b/library/std/src/sys/sync/mutex/itron.rs index 4ba32a8fbcd..b29c7e1d034 100644 --- a/library/std/src/sys/sync/mutex/itron.rs +++ b/library/std/src/sys/sync/mutex/itron.rs @@ -1,5 +1,6 @@ //! Mutex implementation backed by μITRON mutexes. Assumes `acre_mtx` and //! `TA_INHERIT` are available. +#![forbid(unsafe_op_in_unsafe_fn)] use crate::sys::pal::itron::{ abi, diff --git a/library/std/src/sys/sync/rwlock/solid.rs b/library/std/src/sys/sync/rwlock/solid.rs index 7558eee8edd..a8fef685ceb 100644 --- a/library/std/src/sys/sync/rwlock/solid.rs +++ b/library/std/src/sys/sync/rwlock/solid.rs @@ -1,4 +1,5 @@ //! A readers-writer lock implementation backed by the SOLID kernel extension. +#![forbid(unsafe_op_in_unsafe_fn)] use crate::sys::pal::{ abi, diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs index f6cd457046f..e08ac44e1af 100644 --- a/library/std/src/sys/thread_local/guard/windows.rs +++ b/library/std/src/sys/thread_local/guard/windows.rs @@ -78,19 +78,6 @@ pub fn enable() { pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) = tls_callback; unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) { - // See comments above for what this is doing. Note that we don't need this - // trickery on GNU windows, just on MSVC. - #[cfg(all(target_env = "msvc", not(target_thread_local)))] - { - extern "C" { - static _tls_used: u8; - } - - unsafe { - ptr::from_ref(&_tls_used).read_volatile(); - } - } - if dw_reason == c::DLL_THREAD_DETACH || dw_reason == c::DLL_PROCESS_DETACH { #[cfg(target_thread_local)] unsafe { diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 7e38a0996e5..9acd85cddde 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -51,6 +51,7 @@ check-aux: $(Q)$(BOOTSTRAP) test --stage 2 \ src/tools/cargo \ src/tools/cargotest \ + src/etc/test-float-parse \ $(BOOTSTRAP_ARGS) # Run standard library tests in Miri. $(Q)BOOTSTRAP_SKIP_TARGET_SANITY=1 \ diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 8235d4634b7..ed5b9edc86d 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -466,6 +466,7 @@ tool_check_step!(CargoMiri, "src/tools/miri/cargo-miri", SourceType::InTree); tool_check_step!(Rls, "src/tools/rls", SourceType::InTree); tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree); tool_check_step!(MiroptTestTools, "src/tools/miropt-test-tools", SourceType::InTree); +tool_check_step!(TestFloatParse, "src/etc/test-float-parse", SourceType::InTree); tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index 40a2112b192..ee7fb368a8c 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -326,4 +326,5 @@ lint_any!( Rustfmt, "src/tools/rustfmt", "rustfmt"; RustInstaller, "src/tools/rust-installer", "rust-installer"; Tidy, "src/tools/tidy", "tidy"; + TestFloatParse, "src/etc/test-float-parse", "test-float-parse"; ); diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 1e9d2025bc7..7d67cc3b36e 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -1040,6 +1040,8 @@ impl Step for PlainSourceTarball { .arg(builder.src.join("./src/tools/opt-dist/Cargo.toml")) .arg("--sync") .arg(builder.src.join("./src/tools/rustc-perf/Cargo.toml")) + .arg("--sync") + .arg(builder.src.join("./src/tools/rustbook/Cargo.toml")) // Will read the libstd Cargo.toml // which uses the unstable `public-dependency` feature. .env("RUSTC_BOOTSTRAP", "1") diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 633e66afe59..d8204ea00f7 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -1172,6 +1172,12 @@ impl Step for RustcBook { /// in the "md-doc" directory in the build output directory. Then /// "rustbook" is used to convert it to HTML. fn run(self, builder: &Builder<'_>) { + // These submodules are required to be checked out to build rustbook + // because they have Cargo dependencies that are needed. + #[allow(clippy::single_element_loop)] // This will change soon. + for path in ["src/doc/book"] { + builder.update_submodule(Path::new(path)); + } let out_base = builder.md_doc_out(self.target).join("rustc"); t!(fs::create_dir_all(&out_base)); let out_listing = out_base.join("src/lints"); diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 44790301841..f234b08f5e2 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -26,7 +26,6 @@ use crate::{generate_smart_stamp_hash, CLang, GitRepo, Kind}; use crate::utils::exec::command; use build_helper::ci::CiEnv; -use build_helper::git::get_git_merge_base; #[derive(Clone)] pub struct LlvmResult { @@ -154,26 +153,18 @@ pub fn prebuilt_llvm_config(builder: &Builder<'_>, target: TargetSelection) -> L /// This retrieves the LLVM sha we *want* to use, according to git history. pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String { let llvm_sha = if is_git { - // We proceed in 2 steps. First we get the closest commit that is actually upstream. Then we - // walk back further to the last bors merge commit that actually changed LLVM. The first - // step will fail on CI because only the `auto` branch exists; we just fall back to `HEAD` - // in that case. - let closest_upstream = get_git_merge_base(&config.git_config(), Some(&config.src)) - .unwrap_or_else(|_| "HEAD".into()); - let mut rev_list = helpers::git(Some(&config.src)); - rev_list.args(&[ - PathBuf::from("rev-list"), - format!("--author={}", config.stage0_metadata.config.git_merge_commit_email).into(), - "-n1".into(), - "--first-parent".into(), - closest_upstream.into(), - "--".into(), - config.src.join("src/llvm-project"), - config.src.join("src/bootstrap/download-ci-llvm-stamp"), - // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` - config.src.join("src/version"), - ]); - output(rev_list.as_command_mut()).trim().to_owned() + helpers::get_closest_merge_base_commit( + Some(&config.src), + &config.git_config(), + &config.stage0_metadata.config.git_merge_commit_email, + &[ + config.src.join("src/llvm-project"), + config.src.join("src/bootstrap/download-ci-llvm-stamp"), + // the LLVM shared object file is named `LLVM-12-rust-{version}-nightly` + config.src.join("src/version"), + ], + ) + .unwrap() } else if let Some(info) = channel::read_commit_info_file(&config.src) { info.sha.trim().to_owned() } else { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 3f0cbde64e3..cc5931c68db 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3505,3 +3505,80 @@ impl Step for CodegenGCC { cargo.into_cmd().run(builder); } } + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct TestFloatParse { + path: PathBuf, + host: TargetSelection, +} + +impl Step for TestFloatParse { + type Output = (); + const ONLY_HOSTS: bool = true; + const DEFAULT: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/etc/test-float-parse") + } + + fn make_run(run: RunConfig<'_>) { + for path in run.paths { + let path = path.assert_single_path().path.clone(); + run.builder.ensure(Self { path, host: run.target }); + } + } + + fn run(self, builder: &Builder<'_>) { + let bootstrap_host = builder.config.build; + let compiler = builder.compiler(0, bootstrap_host); + let path = self.path.to_str().unwrap(); + let crate_name = self.path.components().last().unwrap().as_os_str().to_str().unwrap(); + + builder.ensure(compile::Std::new(compiler, self.host)); + + // Run any unit tests in the crate + let cargo_test = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolStd, + bootstrap_host, + "test", + path, + SourceType::InTree, + &[], + ); + + run_cargo_test( + cargo_test, + &[], + &[], + crate_name, + crate_name, + compiler, + bootstrap_host, + builder, + ); + + // Run the actual parse tests. + let mut cargo_run = tool::prepare_tool_cargo( + builder, + compiler, + Mode::ToolStd, + bootstrap_host, + "run", + path, + SourceType::InTree, + &[], + ); + + cargo_run.arg("--"); + if builder.config.args().is_empty() { + // By default, exclude tests that take longer than ~1m. + cargo_run.arg("--skip-huge"); + } else { + cargo_run.args(builder.config.args()); + } + + cargo_run.into_cmd().run(builder); + } +} diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 2f8b41334fc..087df2f8a88 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -9,7 +9,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; use crate::utils::exec::{command, BootstrapCommand}; -use crate::utils::helpers::{add_dylib_path, exe, t}; +use crate::utils::helpers::{add_dylib_path, exe, get_closest_merge_base_commit, git, t}; use crate::Compiler; use crate::Mode; use crate::{gha, Kind}; @@ -554,6 +554,57 @@ impl Step for Rustdoc { } let target = target_compiler.host; + let bin_rustdoc = || { + let sysroot = builder.sysroot(target_compiler); + let bindir = sysroot.join("bin"); + t!(fs::create_dir_all(&bindir)); + let bin_rustdoc = bindir.join(exe("rustdoc", target_compiler.host)); + let _ = fs::remove_file(&bin_rustdoc); + bin_rustdoc + }; + + // If CI rustc is enabled and we haven't modified the rustdoc sources, + // use the precompiled rustdoc from CI rustc's sysroot to speed up bootstrapping. + if builder.download_rustc() + && target_compiler.stage > 0 + && builder.rust_info().is_managed_git_subrepository() + { + let commit = get_closest_merge_base_commit( + Some(&builder.config.src), + &builder.config.git_config(), + &builder.config.stage0_metadata.config.git_merge_commit_email, + &[], + ) + .unwrap(); + + let librustdoc_src = builder.config.src.join("src/librustdoc"); + let rustdoc_src = builder.config.src.join("src/tools/rustdoc"); + + // FIXME: The change detection logic here is quite similar to `Config::download_ci_rustc_commit`. + // It would be better to unify them. + let has_changes = !git(Some(&builder.config.src)) + .allow_failure() + .run_always() + .args(["diff-index", "--quiet", &commit]) + .arg("--") + .arg(librustdoc_src) + .arg(rustdoc_src) + .run(builder) + .is_success(); + + if !has_changes { + let precompiled_rustdoc = builder + .config + .ci_rustc_dir() + .join("bin") + .join(exe("rustdoc", target_compiler.host)); + + let bin_rustdoc = bin_rustdoc(); + builder.copy_link(&precompiled_rustdoc, &bin_rustdoc); + return bin_rustdoc; + } + } + let build_compiler = if builder.download_rustc() && target_compiler.stage == 1 { // We already have the stage 1 compiler, we don't need to cut the stage. builder.compiler(target_compiler.stage, builder.config.build) @@ -614,11 +665,7 @@ impl Step for Rustdoc { // don't create a stage0-sysroot/bin directory. if target_compiler.stage > 0 { - let sysroot = builder.sysroot(target_compiler); - let bindir = sysroot.join("bin"); - t!(fs::create_dir_all(&bindir)); - let bin_rustdoc = bindir.join(exe("rustdoc", target_compiler.host)); - let _ = fs::remove_file(&bin_rustdoc); + let bin_rustdoc = bin_rustdoc(); builder.copy_link(&tool_rustdoc, &bin_rustdoc); bin_rustdoc } else { diff --git a/src/bootstrap/src/core/build_steps/vendor.rs b/src/bootstrap/src/core/build_steps/vendor.rs index 62342ee4792..e6b3cb320cf 100644 --- a/src/bootstrap/src/core/build_steps/vendor.rs +++ b/src/bootstrap/src/core/build_steps/vendor.rs @@ -34,8 +34,10 @@ impl Step for Vendor { cmd.arg("--versioned-dirs"); } - // cargo submodule must be present for `x vendor` to work. - builder.build.update_submodule(Path::new("src/tools/cargo")); + // These submodules must be present for `x vendor` to work. + for path in ["src/tools/cargo", "src/doc/book"] { + builder.build.update_submodule(Path::new(path)); + } // Sync these paths by default. for p in [ @@ -44,6 +46,7 @@ impl Step for Vendor { "compiler/rustc_codegen_cranelift/Cargo.toml", "compiler/rustc_codegen_gcc/Cargo.toml", "src/bootstrap/Cargo.toml", + "src/tools/rustbook/Cargo.toml", ] { cmd.arg("--sync").arg(builder.src.join(p)); } diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs index 6d6df650b14..78fbea2e810 100644 --- a/src/bootstrap/src/core/builder.rs +++ b/src/bootstrap/src/core/builder.rs @@ -826,6 +826,7 @@ impl<'a> Builder<'a> { clippy::Rustdoc, clippy::Rustfmt, clippy::RustInstaller, + clippy::TestFloatParse, clippy::Tidy, ), Kind::Check | Kind::Fix => describe!( @@ -840,6 +841,7 @@ impl<'a> Builder<'a> { check::Rls, check::Rustfmt, check::RustAnalyzer, + check::TestFloatParse, check::Bootstrap, ), Kind::Test => describe!( @@ -901,6 +903,7 @@ impl<'a> Builder<'a> { test::RustdocJson, test::HtmlCheck, test::RustInstaller, + test::TestFloatParse, // Run bootstrap close to the end as it's unlikely to fail test::Bootstrap, // Run run-make last, since these won't pass without make on Windows diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index f96633b059a..9d5aa795c6c 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -20,7 +20,7 @@ use crate::core::build_steps::llvm; use crate::core::config::flags::{Color, Flags, Warnings}; use crate::utils::cache::{Interned, INTERNER}; use crate::utils::channel::{self, GitInfo}; -use crate::utils::helpers::{self, exe, output, t}; +use crate::utils::helpers::{self, exe, get_closest_merge_base_commit, output, t}; use build_helper::exit; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -2471,14 +2471,13 @@ impl Config { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let merge_base = output( - helpers::git(Some(&self.src)) - .arg("rev-list") - .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) - .args(["-n1", "--first-parent", "HEAD"]) - .as_command_mut(), - ); - let commit = merge_base.trim_end(); + let commit = get_closest_merge_base_commit( + Some(&self.src), + &self.git_config(), + &self.stage0_metadata.config.git_merge_commit_email, + &[], + ) + .unwrap(); if commit.is_empty() { println!("ERROR: could not find commit hash for downloading rustc"); println!("HELP: maybe your repository history is too shallow?"); @@ -2489,7 +2488,7 @@ impl Config { // Warn if there were changes to the compiler or standard library since the ancestor commit. let has_changes = !t!(helpers::git(Some(&self.src)) - .args(["diff-index", "--quiet", commit]) + .args(["diff-index", "--quiet", &commit]) .arg("--") .args([self.src.join("compiler"), self.src.join("library")]) .as_command_mut() @@ -2565,14 +2564,13 @@ impl Config { ) -> Option<String> { // Look for a version to compare to based on the current commit. // Only commits merged by bors will have CI artifacts. - let merge_base = output( - helpers::git(Some(&self.src)) - .arg("rev-list") - .arg(format!("--author={}", self.stage0_metadata.config.git_merge_commit_email)) - .args(["-n1", "--first-parent", "HEAD"]) - .as_command_mut(), - ); - let commit = merge_base.trim_end(); + let commit = get_closest_merge_base_commit( + Some(&self.src), + &self.git_config(), + &self.stage0_metadata.config.git_merge_commit_email, + &[], + ) + .unwrap(); if commit.is_empty() { println!("error: could not find commit hash for downloading components from CI"); println!("help: maybe your repository history is too shallow?"); @@ -2583,7 +2581,7 @@ impl Config { // Warn if there were changes to the compiler or standard library since the ancestor commit. let mut git = helpers::git(Some(&self.src)); - git.args(["diff-index", "--quiet", commit, "--"]); + git.args(["diff-index", "--quiet", &commit, "--"]); // Handle running from a directory other than the top level let top_level = &self.src; diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index d2910f8edc6..79bea50c626 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -439,7 +439,7 @@ impl Build { // Make sure we update these before gathering metadata so we don't get an error about missing // Cargo.toml files. - let rust_submodules = ["src/doc/book", "library/backtrace", "library/stdarch"]; + let rust_submodules = ["library/backtrace", "library/stdarch"]; for s in rust_submodules { build.update_submodule(Path::new(s)); } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 3c82fa189be..690d7318f94 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -3,6 +3,7 @@ //! Simple things like testing the various filesystem operations here and there, //! not a lot of interesting happenings here unfortunately. +use build_helper::git::{get_git_merge_base, output_result, GitConfig}; use build_helper::util::fail; use std::env; use std::ffi::OsStr; @@ -202,7 +203,9 @@ pub fn target_supports_cranelift_backend(target: TargetSelection) -> bool { || target.contains("aarch64") || target.contains("s390x") || target.contains("riscv64gc") - } else if target.contains("darwin") || target.is_windows() { + } else if target.contains("darwin") { + target.contains("x86_64") || target.contains("aarch64") + } else if target.is_windows() { target.contains("x86_64") } else { false @@ -521,3 +524,26 @@ pub fn git(source_dir: Option<&Path>) -> BootstrapCommand { git } + +/// Returns the closest commit available from upstream for the given `author` and `target_paths`. +/// +/// If it fails to find the commit from upstream using `git merge-base`, fallbacks to HEAD. +pub fn get_closest_merge_base_commit( + source_dir: Option<&Path>, + config: &GitConfig<'_>, + author: &str, + target_paths: &[PathBuf], +) -> Result<String, String> { + let mut git = git(source_dir).capture_stdout(); + + let merge_base = get_git_merge_base(config, source_dir).unwrap_or_else(|_| "HEAD".into()); + + git.arg(Path::new("rev-list")); + git.args([&format!("--author={author}"), "-n1", "--first-parent", &merge_base]); + + if !target_paths.is_empty() { + git.arg("--").args(target_paths); + } + + Ok(output_result(git.as_command_mut())?.trim().to_owned()) +} 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 962484593b4..2621e9a6031 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -85,9 +85,9 @@ RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc sun COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/ RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh -RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-22/wasi-sdk-22.0-linux.tar.gz | \ +RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-23/wasi-sdk-23.0-x86_64-linux.tar.gz | \ tar -xz -ENV WASI_SDK_PATH=/tmp/wasi-sdk-22.0 +ENV WASI_SDK_PATH=/tmp/wasi-sdk-23.0-x86_64-linux COPY scripts/freebsd-toolchain.sh /tmp/ RUN /tmp/freebsd-toolchain.sh i686 diff --git a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in index c7b3376e2f1..d7c2d3fde5b 100644 --- a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in +++ b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.in @@ -11,4 +11,4 @@ # pip-compile --allow-unsafe --generate-hashes reuse-requirements.in # -reuse +reuse>=4.0,<5.0 diff --git a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt index b0f598f77ea..8784e18864b 100644 --- a/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt +++ b/src/ci/docker/host-x86_64/mingw-check/reuse-requirements.txt @@ -4,6 +4,10 @@ # # pip-compile --allow-unsafe --generate-hashes reuse-requirements.in # +attrs==23.2.0 \ + --hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \ + --hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1 + # via reuse binaryornot==0.4.4 \ --hash=sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061 \ --hash=sha256:b8b71173c917bddcd2c16070412e369c3ed7f0528926f70cac18a6c97fd563e4 @@ -14,71 +18,91 @@ boolean-py==4.0 \ # via # license-expression # reuse -chardet==5.1.0 \ - --hash=sha256:0d62712b956bc154f85fb0a266e2a3c5913c2967e00348701b32411d6def31e5 \ - --hash=sha256:362777fb014af596ad31334fde1e8c327dfdb076e1960d1694662d46a6917ab9 +chardet==5.2.0 \ + --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \ + --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970 # via # binaryornot # python-debian -jinja2==3.1.2 \ - --hash=sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852 \ - --hash=sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61 +jinja2==3.1.4 \ + --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ + --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d # via reuse -license-expression==30.0.0 \ - --hash=sha256:ad638292aa8493f84354909b517922cb823582c2ce2c4d880e42544a86bea8dd \ - --hash=sha256:e95325110110eb2b7539ee7773b97a0724d5371ec563cc718c8cac0e38cc40cc +license-expression==30.3.0 \ + --hash=sha256:1295406f736b4f395ff069aec1cebfad53c0fcb3cf57df0f5ec58fc7b905aea5 \ + --hash=sha256:ae0ba9a829d6909c785dc2f0131f13d10d68318e4a5f28af5ef152d6b52f9b41 # via reuse -markupsafe==2.1.1 \ - --hash=sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003 \ - --hash=sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88 \ - --hash=sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5 \ - --hash=sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7 \ - --hash=sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a \ - --hash=sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603 \ - --hash=sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1 \ - --hash=sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135 \ - --hash=sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247 \ - --hash=sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6 \ - --hash=sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601 \ - --hash=sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77 \ - --hash=sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02 \ - --hash=sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e \ - --hash=sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63 \ - --hash=sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f \ - --hash=sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980 \ - --hash=sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b \ - --hash=sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812 \ - --hash=sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff \ - --hash=sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96 \ - --hash=sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1 \ - --hash=sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925 \ - --hash=sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a \ - --hash=sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6 \ - --hash=sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e \ - --hash=sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f \ - --hash=sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4 \ - --hash=sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f \ - --hash=sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3 \ - --hash=sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c \ - --hash=sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a \ - --hash=sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417 \ - --hash=sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a \ - --hash=sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a \ - --hash=sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37 \ - --hash=sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452 \ - --hash=sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933 \ - --hash=sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a \ - --hash=sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7 +markupsafe==2.1.5 \ + --hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \ + --hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \ + --hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \ + --hash=sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3 \ + --hash=sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532 \ + --hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \ + --hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \ + --hash=sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df \ + --hash=sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4 \ + --hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \ + --hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \ + --hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \ + --hash=sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8 \ + --hash=sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371 \ + --hash=sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2 \ + --hash=sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465 \ + --hash=sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52 \ + --hash=sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6 \ + --hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \ + --hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \ + --hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \ + --hash=sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0 \ + --hash=sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029 \ + --hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \ + --hash=sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a \ + --hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \ + --hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \ + --hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \ + --hash=sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf \ + --hash=sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9 \ + --hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \ + --hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \ + --hash=sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3 \ + --hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \ + --hash=sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46 \ + --hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \ + --hash=sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a \ + --hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \ + --hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \ + --hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \ + --hash=sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea \ + --hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \ + --hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \ + --hash=sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e \ + --hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \ + --hash=sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f \ + --hash=sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50 \ + --hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \ + --hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \ + --hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \ + --hash=sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff \ + --hash=sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2 \ + --hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \ + --hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \ + --hash=sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf \ + --hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \ + --hash=sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5 \ + --hash=sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab \ + --hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd \ + --hash=sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68 # via jinja2 python-debian==0.1.49 \ --hash=sha256:880f3bc52e31599f2a9b432bd7691844286825087fccdcf2f6ffd5cd79a26f9f \ --hash=sha256:8cf677a30dbcb4be7a99536c17e11308a827a4d22028dc59a67f6c6dd3f0f58c # via reuse -reuse==1.1.0 \ - --hash=sha256:7a054f6e372ad02d0b1b07368030fc38746b50ed45f5422a81994e7a88b52f1f \ - --hash=sha256:b0f3fb9091ff513af04b555d14a4c529ab05f6a575ab192dd9b68244f1e0721d +reuse==4.0.3 \ + --hash=sha256:4f2c3e1213ec644e5febc50d8322d18982e4e1102af8a51d9493bfc2164a0eac \ + --hash=sha256:b33e26ec1d105cfcfc2e904d103faec0d758994278feb95a4f4290a864562243 # via -r reuse-requirements.in -setuptools==66.0.0 \ - --hash=sha256:a78d01d1e2c175c474884671dde039962c9d74c7223db7369771fcf6e29ceeab \ - --hash=sha256:bd6eb2d6722568de6d14b87c44a96fac54b2a45ff5e940e639979a3d1792adb6 +tomlkit==0.13.0 \ + --hash=sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72 \ + --hash=sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264 # via reuse diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index f874b2ed475..c2f5a87b123 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -40,9 +40,9 @@ WORKDIR / COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh -RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-22/wasi-sdk-22.0-linux.tar.gz | \ +RUN curl -L https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-23/wasi-sdk-23.0-x86_64-linux.tar.gz | \ tar -xz -ENV WASI_SDK_PATH=/wasi-sdk-22.0 +ENV WASI_SDK_PATH=/wasi-sdk-23.0-x86_64-linux ENV RUST_CONFIGURE_ARGS \ --musl-root-x86_64=/usr/local/x86_64-linux-musl \ diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index a6e12c6ff95..638f14ad53f 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -326,6 +326,7 @@ auto: NO_DEBUG_ASSERTIONS: 1 NO_OVERFLOW_CHECKS: 1 DIST_REQUIRE_ALL_TOOLS: 1 + CODEGEN_BACKENDS: llvm,cranelift <<: *job-macos-m1 # This target only needs to support 11.0 and up as nothing else supports the hardware diff --git a/src/ci/run.sh b/src/ci/run.sh index 869f75e923d..c8201d9bcfd 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -19,7 +19,7 @@ if [ "$NO_CHANGE_USER" = "" ]; then # already be running with the right user. # # For NO_CHANGE_USER done in the small number of Dockerfiles affected. - echo -e '[safe]\n\tdirectory = *' > /home/user/gitconfig + echo -e '[safe]\n\tdirectory = *' > /home/user/.gitconfig exec su --preserve-environment -c "env PATH=$PATH \"$0\"" user fi diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 4a1c0916253..c02c9aebe7e 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -38,33 +38,10 @@ they will both appear in documentation. Rustdoc does not have a magic way to compile documentation 'as-if' you'd run it once for each platform (such a magic wand has been called the ['holy grail of rustdoc'][#1998]). Instead, it sees *all* of your code at once, the same way the Rust compiler would if you passed it -`--cfg doc`. However, Rustdoc has a trick up its sleeve to handle platform-specific code if it -*does* receive it. - -To document your crate, Rustdoc only needs to know the public signature of your functions. -In particular, it doesn't have to know how any of your functions are implemented, so it ignores -all type errors and name resolution errors with function bodies. Note that this does *not* -work for anything outside a function body: since Rustdoc documents your types, it has to -know what those types are! For example, this code will work regardless of the platform: - -```rust,ignore (platform-specific,rustdoc-specific-behavior) -pub fn f() { - use std::os::windows::ffi::OsStrExt; -} -``` - -but this will not, because the unknown type is part of the function signature: - -```rust,ignore (platform-specific,rustdoc-specific-behavior) -pub fn f() -> std::os::windows::ffi::EncodeWide<'static> { - unimplemented!() -} -``` - -For a more realistic example of code this allows, see [the rustdoc test suite][realistic-async]. +`--cfg doc`. The main difference is that rustdoc doesn't run all the compiler passes, meaning +that some invalid code won't emit an error. [#1998]: https://github.com/rust-lang/rust/issues/1998 -[realistic-async]: https://github.com/rust-lang/rust/blob/b146000e910ccd60bdcde89363cb6aa14ecc0d95/src/test/rustdoc-ui/error-in-impl-trait/realistic-async.rs ## Add aliases for an item in documentation search diff --git a/src/etc/test-float-parse/Cargo.toml b/src/etc/test-float-parse/Cargo.toml index a045be956ac..56cb5cddeea 100644 --- a/src/etc/test-float-parse/Cargo.toml +++ b/src/etc/test-float-parse/Cargo.toml @@ -4,11 +4,12 @@ version = "0.1.0" edition = "2021" publish = false -[workspace] -resolver = "1" - [dependencies] -rand = "0.8" +indicatif = { version = "0.17.8", default-features = false } +num = "0.4.3" +rand = "0.8.5" +rand_chacha = "0.3" +rayon = "1" [lib] name = "test_float_parse" diff --git a/src/etc/test-float-parse/README.md b/src/etc/test-float-parse/README.md new file mode 100644 index 00000000000..21b20d0a072 --- /dev/null +++ b/src/etc/test-float-parse/README.md @@ -0,0 +1,55 @@ +# Float Parsing Tests + +These are tests designed to test decimal to float conversions (`dec2flt`) used +by the standard library. + +It consistes of a collection of test generators that each generate a set of +patterns intended to test a specific property. In addition, there are exhaustive +tests (for <= `f32`) and fuzzers (for anything that can't be run exhaustively). + +The generators work as follows: + +- Each generator is a struct that lives somewhere in the `gen` module. Usually + it is generic over a float type. +- These generators must implement `Iterator`, which should return a context type + that can be used to construct a test string (but usually not the string + itself). +- They must also implement the `Generator` trait, which provides a method to + write test context to a string as a test case, as well as some extra metadata. + + The split between context generation and string construction is so that we can + reuse string allocations. +- Each generator gets registered once for each float type. Each of these + generators then get their iterator called, and each test case checked against + the float type's parse implementation. + +Some generators produce decimal strings, others create bit patterns that need to +be bitcasted to the float type, which then uses its `Display` implementation to +write to a string. For these, float to decimal (`flt2dec`) conversions also get +tested, if unintentionally. + +For each test case, the following is done: + +- The test string is parsed to the float type using the standard library's + implementation. +- The test string is parsed separately to a `BigRational`, which acts as a + representation with infinite precision. +- The rational value then gets checked that it is within the float's + representable values (absolute value greater than the smallest number to round + to zero, but less less than the first value to round to infinity). If these + limits are exceeded, check that the parsed float reflects that. +- For real nonzero numbers, the parsed float is converted into a rational using + `significand * 2^exponent`. It is then checked against the actual rational + value, and verified to be within half a bit's precision of the parsed value. + Also it is checked that ties round to even. + +This is all highly parallelized with `rayon`; test generators can run in +parallel, and their tests get chunked and run in parallel. + +There is a simple command line that allows filtering which tests are run, +setting the number of iterations for fuzzing tests, limiting failures, setting +timeouts, etc. See `main.rs` or run with `--help` for options. + +Note that when running via `./x`, only tests that take less than a few minutes +are run by default. Navigate to the crate (or pass `-C` to Cargo) and run it +directly to run all tests or pass specific arguments. diff --git a/src/etc/test-float-parse/runtests.py b/src/etc/test-float-parse/runtests.py deleted file mode 100755 index cc5e31a051f..00000000000 --- a/src/etc/test-float-parse/runtests.py +++ /dev/null @@ -1,394 +0,0 @@ -#!/usr/bin/env python3 - -""" -Testing dec2flt -=============== -These are *really* extensive tests. Expect them to run for hours. Due to the -nature of the problem (the input is a string of arbitrary length), exhaustive -testing is not really possible. Instead, there are exhaustive tests for some -classes of inputs for which that is feasible and a bunch of deterministic and -random non-exhaustive tests for covering everything else. - -The actual tests (generating decimal strings and feeding them to dec2flt) is -performed by a set of stand-along rust programs. This script compiles, runs, -and supervises them. The programs report the strings they generate and the -floating point numbers they converted those strings to, and this script -checks that the results are correct. - -You can run specific tests rather than all of them by giving their names -(without .rs extension) as command line parameters. - -Verification ------------- -The tricky part is not generating those inputs but verifying the outputs. -Comparing with the result of Python's float() does not cut it because -(and this is apparently undocumented) although Python includes a version of -Martin Gay's code including the decimal-to-float part, it doesn't actually use -it for float() (only for round()) instead relying on the system scanf() which -is not necessarily completely accurate. - -Instead, we take the input and compute the true value with bignum arithmetic -(as a fraction, using the ``fractions`` module). - -Given an input string and the corresponding float computed via Rust, simply -decode the float into f * 2^k (for integers f, k) and the ULP. -We can now easily compute the error and check if it is within 0.5 ULP as it -should be. Zero and infinites are handled similarly: - -- If the approximation is 0.0, the exact value should be *less or equal* - half the smallest denormal float: the smallest denormal floating point - number has an odd mantissa (00...001) and thus half of that is rounded - to 00...00, i.e., zero. -- If the approximation is Inf, the exact value should be *greater or equal* - to the largest finite float + 0.5 ULP: the largest finite float has an odd - mantissa (11...11), so that plus half an ULP is rounded up to the nearest - even number, which overflows. - -Implementation details ----------------------- -This directory contains a set of single-file Rust programs that perform -tests with a particular class of inputs. Each is compiled and run without -parameters, outputs (f64, f32, decimal) pairs to verify externally, and -in any case either exits gracefully or with a panic. - -If a test binary writes *anything at all* to stderr or exits with an -exit code that's not 0, the test fails. -The output on stdout is treated as (f64, f32, decimal) record, encoded thusly: - -- First, the bits of the f64 encoded as an ASCII hex string. -- Second, the bits of the f32 encoded as an ASCII hex string. -- Then the corresponding string input, in ASCII -- The record is terminated with a newline. - -Incomplete records are an error. Not-a-Number bit patterns are invalid too. - -The tests run serially but the validation for a single test is parallelized -with ``multiprocessing``. Each test is launched as a subprocess. -One thread supervises it: Accepts and enqueues records to validate, observe -stderr, and waits for the process to exit. A set of worker processes perform -the validation work for the outputs enqueued there. Another thread listens -for progress updates from the workers. - -Known issues ------------- -Some errors (e.g., NaN outputs) aren't handled very gracefully. -Also, if there is an exception or the process is interrupted (at least on -Windows) the worker processes are leaked and stick around forever. -They're only a few megabytes each, but still, this script should not be run -if you aren't prepared to manually kill a lot of orphaned processes. -""" -from __future__ import print_function -import sys -import os.path -import time -import struct -from fractions import Fraction -from collections import namedtuple -from subprocess import Popen, check_call, PIPE -from glob import glob -import multiprocessing -import threading -import ctypes -import binascii - -try: # Python 3 - import queue as Queue -except ImportError: # Python 2 - import Queue - -NUM_WORKERS = 2 -UPDATE_EVERY_N = 50000 -INF = namedtuple('INF', '')() -NEG_INF = namedtuple('NEG_INF', '')() -ZERO = namedtuple('ZERO', '')() -MAILBOX = None # The queue for reporting errors to the main process. -STDOUT_LOCK = threading.Lock() -test_name = None -child_processes = [] -exit_status = 0 - -def msg(*args): - with STDOUT_LOCK: - print("[" + test_name + "]", *args) - sys.stdout.flush() - - -def write_errors(): - global exit_status - f = open("errors.txt", 'w') - have_seen_error = False - while True: - args = MAILBOX.get() - if args is None: - f.close() - break - print(*args, file=f) - f.flush() - if not have_seen_error: - have_seen_error = True - msg("Something is broken:", *args) - msg("Future errors will be logged to errors.txt") - exit_status = 101 - - -def cargo(): - print("compiling tests") - sys.stdout.flush() - check_call(['cargo', 'build', '--release']) - - -def run(test): - global test_name - test_name = test - - t0 = time.perf_counter() - msg("setting up supervisor") - command = ['cargo', 'run', '--bin', test, '--release'] - proc = Popen(command, bufsize=1<<20 , stdin=PIPE, stdout=PIPE, stderr=PIPE) - done = multiprocessing.Value(ctypes.c_bool) - queue = multiprocessing.Queue(maxsize=5)#(maxsize=1024) - workers = [] - for n in range(NUM_WORKERS): - worker = multiprocessing.Process(name='Worker-' + str(n + 1), - target=init_worker, - args=[test, MAILBOX, queue, done]) - workers.append(worker) - child_processes.append(worker) - for worker in workers: - worker.start() - msg("running test") - interact(proc, queue) - with done.get_lock(): - done.value = True - for worker in workers: - worker.join() - msg("python is done") - assert queue.empty(), "did not validate everything" - dt = time.perf_counter() - t0 - msg("took", round(dt, 3), "seconds") - - -def interact(proc, queue): - n = 0 - while proc.poll() is None: - line = proc.stdout.readline() - if not line: - continue - assert line.endswith(b'\n'), "incomplete line: " + repr(line) - queue.put(line) - n += 1 - if n % UPDATE_EVERY_N == 0: - msg("got", str(n // 1000) + "k", "records") - msg("rust is done. exit code:", proc.returncode) - rest, stderr = proc.communicate() - if stderr: - msg("rust stderr output:", stderr) - for line in rest.split(b'\n'): - if not line: - continue - queue.put(line) - - -def main(): - global MAILBOX - files = glob('src/bin/*.rs') - basenames = [os.path.basename(i) for i in files] - all_tests = [os.path.splitext(f)[0] for f in basenames if not f.startswith('_')] - args = sys.argv[1:] - if args: - tests = [test for test in all_tests if test in args] - else: - tests = all_tests - if not tests: - print("Error: No tests to run") - sys.exit(1) - # Compile first for quicker feedback - cargo() - # Set up mailbox once for all tests - MAILBOX = multiprocessing.Queue() - mailman = threading.Thread(target=write_errors) - mailman.daemon = True - mailman.start() - for test in tests: - run(test) - MAILBOX.put(None) - mailman.join() - - -# ---- Worker thread code ---- - - -POW2 = { e: Fraction(2) ** e for e in range(-1100, 1100) } -HALF_ULP = { e: (Fraction(2) ** e)/2 for e in range(-1100, 1100) } -DONE_FLAG = None - - -def send_error_to_supervisor(*args): - MAILBOX.put(args) - - -def init_worker(test, mailbox, queue, done): - global test_name, MAILBOX, DONE_FLAG - test_name = test - MAILBOX = mailbox - DONE_FLAG = done - do_work(queue) - - -def is_done(): - with DONE_FLAG.get_lock(): - return DONE_FLAG.value - - -def do_work(queue): - while True: - try: - line = queue.get(timeout=0.01) - except Queue.Empty: - if queue.empty() and is_done(): - return - else: - continue - bin64, bin32, text = line.rstrip().split() - validate(bin64, bin32, text.decode('utf-8')) - - -def decode_binary64(x): - """ - Turn a IEEE 754 binary64 into (mantissa, exponent), except 0.0 and - infinity (positive and negative), which return ZERO, INF, and NEG_INF - respectively. - """ - x = binascii.unhexlify(x) - assert len(x) == 8, repr(x) - [bits] = struct.unpack(b'>Q', x) - if bits == 0: - return ZERO - exponent = (bits >> 52) & 0x7FF - negative = bits >> 63 - low_bits = bits & 0xFFFFFFFFFFFFF - if exponent == 0: - mantissa = low_bits - exponent += 1 - if mantissa == 0: - return ZERO - elif exponent == 0x7FF: - assert low_bits == 0, "NaN" - if negative: - return NEG_INF - else: - return INF - else: - mantissa = low_bits | (1 << 52) - exponent -= 1023 + 52 - if negative: - mantissa = -mantissa - return (mantissa, exponent) - - -def decode_binary32(x): - """ - Turn a IEEE 754 binary32 into (mantissa, exponent), except 0.0 and - infinity (positive and negative), which return ZERO, INF, and NEG_INF - respectively. - """ - x = binascii.unhexlify(x) - assert len(x) == 4, repr(x) - [bits] = struct.unpack(b'>I', x) - if bits == 0: - return ZERO - exponent = (bits >> 23) & 0xFF - negative = bits >> 31 - low_bits = bits & 0x7FFFFF - if exponent == 0: - mantissa = low_bits - exponent += 1 - if mantissa == 0: - return ZERO - elif exponent == 0xFF: - if negative: - return NEG_INF - else: - return INF - else: - mantissa = low_bits | (1 << 23) - exponent -= 127 + 23 - if negative: - mantissa = -mantissa - return (mantissa, exponent) - - -MIN_SUBNORMAL_DOUBLE = Fraction(2) ** -1074 -MIN_SUBNORMAL_SINGLE = Fraction(2) ** -149 # XXX unsure -MAX_DOUBLE = (2 - Fraction(2) ** -52) * (2 ** 1023) -MAX_SINGLE = (2 - Fraction(2) ** -23) * (2 ** 127) -MAX_ULP_DOUBLE = 1023 - 52 -MAX_ULP_SINGLE = 127 - 23 -DOUBLE_ZERO_CUTOFF = MIN_SUBNORMAL_DOUBLE / 2 -DOUBLE_INF_CUTOFF = MAX_DOUBLE + 2 ** (MAX_ULP_DOUBLE - 1) -SINGLE_ZERO_CUTOFF = MIN_SUBNORMAL_SINGLE / 2 -SINGLE_INF_CUTOFF = MAX_SINGLE + 2 ** (MAX_ULP_SINGLE - 1) - -def validate(bin64, bin32, text): - try: - double = decode_binary64(bin64) - except AssertionError: - print(bin64, bin32, text) - raise - single = decode_binary32(bin32) - real = Fraction(text) - - if double is ZERO: - if real > DOUBLE_ZERO_CUTOFF: - record_special_error(text, "f64 zero") - elif double is INF: - if real < DOUBLE_INF_CUTOFF: - record_special_error(text, "f64 inf") - elif double is NEG_INF: - if -real < DOUBLE_INF_CUTOFF: - record_special_error(text, "f64 -inf") - elif len(double) == 2: - sig, k = double - validate_normal(text, real, sig, k, "f64") - else: - assert 0, "didn't handle binary64" - if single is ZERO: - if real > SINGLE_ZERO_CUTOFF: - record_special_error(text, "f32 zero") - elif single is INF: - if real < SINGLE_INF_CUTOFF: - record_special_error(text, "f32 inf") - elif single is NEG_INF: - if -real < SINGLE_INF_CUTOFF: - record_special_error(text, "f32 -inf") - elif len(single) == 2: - sig, k = single - validate_normal(text, real, sig, k, "f32") - else: - assert 0, "didn't handle binary32" - -def record_special_error(text, descr): - send_error_to_supervisor(text.strip(), "wrongly rounded to", descr) - - -def validate_normal(text, real, sig, k, kind): - approx = sig * POW2[k] - error = abs(approx - real) - if error > HALF_ULP[k]: - record_normal_error(text, error, k, kind) - - -def record_normal_error(text, error, k, kind): - one_ulp = HALF_ULP[k + 1] - assert one_ulp == 2 * HALF_ULP[k] - relative_error = error / one_ulp - text = text.strip() - try: - err_repr = float(relative_error) - except ValueError: - err_repr = str(err_repr).replace('/', ' / ') - send_error_to_supervisor(err_repr, "ULP error on", text, "(" + kind + ")") - - -if __name__ == '__main__': - main() diff --git a/src/etc/test-float-parse/src/bin/few-ones.rs b/src/etc/test-float-parse/src/bin/few-ones.rs deleted file mode 100644 index 6bb406a5947..00000000000 --- a/src/etc/test-float-parse/src/bin/few-ones.rs +++ /dev/null @@ -1,15 +0,0 @@ -use test_float_parse::validate; - -fn main() { - let mut pow = vec![]; - for i in 0..63 { - pow.push(1u64 << i); - } - for a in &pow { - for b in &pow { - for c in &pow { - validate(&(a | b | c).to_string()); - } - } - } -} diff --git a/src/etc/test-float-parse/src/bin/huge-pow10.rs b/src/etc/test-float-parse/src/bin/huge-pow10.rs deleted file mode 100644 index 722a24ffcd8..00000000000 --- a/src/etc/test-float-parse/src/bin/huge-pow10.rs +++ /dev/null @@ -1,9 +0,0 @@ -use test_float_parse::validate; - -fn main() { - for e in 300..310 { - for i in 0..100000 { - validate(&format!("{}e{}", i, e)); - } - } -} diff --git a/src/etc/test-float-parse/src/bin/long-fractions.rs b/src/etc/test-float-parse/src/bin/long-fractions.rs deleted file mode 100644 index c715bc1ac2b..00000000000 --- a/src/etc/test-float-parse/src/bin/long-fractions.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::char; -use test_float_parse::validate; - -fn main() { - for n in 0..10 { - let digit = char::from_digit(n, 10).unwrap(); - let mut s = "0.".to_string(); - for _ in 0..400 { - s.push(digit); - if s.parse::<f64>().is_ok() { - validate(&s); - } - } - } -} diff --git a/src/etc/test-float-parse/src/bin/many-digits.rs b/src/etc/test-float-parse/src/bin/many-digits.rs deleted file mode 100644 index ba166fd5607..00000000000 --- a/src/etc/test-float-parse/src/bin/many-digits.rs +++ /dev/null @@ -1,25 +0,0 @@ -extern crate rand; - -use rand::distributions::{Range, Sample}; -use rand::{IsaacRng, Rng, SeedableRng}; -use std::char; -use test_float_parse::{validate, SEED}; - -fn main() { - let mut rnd = IsaacRng::from_seed(&SEED); - let mut range = Range::new(0, 10); - for _ in 0..5_000_000u64 { - let num_digits = rnd.gen_range(100, 400); - let digits = gen_digits(num_digits, &mut range, &mut rnd); - validate(&digits); - } -} - -fn gen_digits<R: Rng>(n: u32, range: &mut Range<u32>, rnd: &mut R) -> String { - let mut s = String::new(); - for _ in 0..n { - let digit = char::from_digit(range.sample(rnd), 10).unwrap(); - s.push(digit); - } - s -} diff --git a/src/etc/test-float-parse/src/bin/rand-f64.rs b/src/etc/test-float-parse/src/bin/rand-f64.rs deleted file mode 100644 index 6991e8be15e..00000000000 --- a/src/etc/test-float-parse/src/bin/rand-f64.rs +++ /dev/null @@ -1,18 +0,0 @@ -extern crate rand; - -use rand::{IsaacRng, Rng, SeedableRng}; -use std::mem::transmute; -use test_float_parse::{validate, SEED}; - -fn main() { - let mut rnd = IsaacRng::from_seed(&SEED); - let mut i = 0; - while i < 10_000_000 { - let bits = rnd.next_u64(); - let x: f64 = unsafe { transmute(bits) }; - if x.is_finite() { - validate(&format!("{:e}", x)); - i += 1; - } - } -} diff --git a/src/etc/test-float-parse/src/bin/short-decimals.rs b/src/etc/test-float-parse/src/bin/short-decimals.rs deleted file mode 100644 index 49084eb35e8..00000000000 --- a/src/etc/test-float-parse/src/bin/short-decimals.rs +++ /dev/null @@ -1,17 +0,0 @@ -use test_float_parse::validate; - -fn main() { - // Skip e = 0 because small-u32 already does those. - for e in 1..301 { - for i in 0..10000 { - // If it ends in zeros, the parser will strip those (and adjust the exponent), - // which almost always (except for exponents near +/- 300) result in an input - // equivalent to something we already generate in a different way. - if i % 10 == 0 { - continue; - } - validate(&format!("{}e{}", i, e)); - validate(&format!("{}e-{}", i, e)); - } - } -} diff --git a/src/etc/test-float-parse/src/bin/subnorm.rs b/src/etc/test-float-parse/src/bin/subnorm.rs deleted file mode 100644 index ac88747eacd..00000000000 --- a/src/etc/test-float-parse/src/bin/subnorm.rs +++ /dev/null @@ -1,11 +0,0 @@ -use std::mem::transmute; -use test_float_parse::validate; - -fn main() { - for bits in 0u32..(1 << 21) { - let single: f32 = unsafe { transmute(bits) }; - validate(&format!("{:e}", single)); - let double: f64 = unsafe { transmute(bits as u64) }; - validate(&format!("{:e}", double)); - } -} diff --git a/src/etc/test-float-parse/src/bin/tiny-pow10.rs b/src/etc/test-float-parse/src/bin/tiny-pow10.rs deleted file mode 100644 index fb6ba166380..00000000000 --- a/src/etc/test-float-parse/src/bin/tiny-pow10.rs +++ /dev/null @@ -1,9 +0,0 @@ -use test_float_parse::validate; - -fn main() { - for e in 301..327 { - for i in 0..100000 { - validate(&format!("{}e-{}", i, e)); - } - } -} diff --git a/src/etc/test-float-parse/src/bin/u32-small.rs b/src/etc/test-float-parse/src/bin/u32-small.rs deleted file mode 100644 index 5ec9d1eea5f..00000000000 --- a/src/etc/test-float-parse/src/bin/u32-small.rs +++ /dev/null @@ -1,7 +0,0 @@ -use test_float_parse::validate; - -fn main() { - for i in 0..(1 << 19) { - validate(&i.to_string()); - } -} diff --git a/src/etc/test-float-parse/src/bin/u64-pow2.rs b/src/etc/test-float-parse/src/bin/u64-pow2.rs deleted file mode 100644 index 984e49200cd..00000000000 --- a/src/etc/test-float-parse/src/bin/u64-pow2.rs +++ /dev/null @@ -1,15 +0,0 @@ -use test_float_parse::validate; - -fn main() { - for exp in 19..64 { - let power: u64 = 1 << exp; - validate(&power.to_string()); - for offset in 1..123 { - validate(&(power + offset).to_string()); - validate(&(power - offset).to_string()); - } - } - for offset in 0..123 { - validate(&(u64::MAX - offset).to_string()); - } -} diff --git a/src/etc/test-float-parse/src/gen/exhaustive.rs b/src/etc/test-float-parse/src/gen/exhaustive.rs new file mode 100644 index 00000000000..5d4b6df8e59 --- /dev/null +++ b/src/etc/test-float-parse/src/gen/exhaustive.rs @@ -0,0 +1,43 @@ +use std::fmt::Write; +use std::ops::RangeInclusive; + +use crate::{Float, Generator, Int}; + +/// Test every possible bit pattern. This is infeasible to run on any float types larger than +/// `f32` (which takes about an hour). +pub struct Exhaustive<F: Float> { + iter: RangeInclusive<F::Int>, +} + +impl<F: Float> Generator<F> for Exhaustive<F> +where + RangeInclusive<F::Int>: Iterator<Item = F::Int>, +{ + const NAME: &'static str = "exhaustive"; + const SHORT_NAME: &'static str = "exhaustive"; + + type WriteCtx = F; + + fn total_tests() -> u64 { + F::Int::MAX.try_into().unwrap_or(u64::MAX) + } + + fn new() -> Self { + Self { iter: F::Int::ZERO..=F::Int::MAX } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl<F: Float> Iterator for Exhaustive<F> +where + RangeInclusive<F::Int>: Iterator<Item = F::Int>, +{ + type Item = F; + + fn next(&mut self) -> Option<Self::Item> { + Some(F::from_bits(self.iter.next()?)) + } +} diff --git a/src/etc/test-float-parse/src/gen/exponents.rs b/src/etc/test-float-parse/src/gen/exponents.rs new file mode 100644 index 00000000000..3748e9d380c --- /dev/null +++ b/src/etc/test-float-parse/src/gen/exponents.rs @@ -0,0 +1,95 @@ +use std::fmt::Write; +use std::ops::RangeInclusive; + +use crate::traits::BoxGenIter; +use crate::{Float, Generator}; + +const SMALL_COEFF_MAX: i32 = 10_000; +const SMALL_EXP_MAX: i32 = 300; + +const SMALL_COEFF_RANGE: RangeInclusive<i32> = (-SMALL_COEFF_MAX)..=SMALL_COEFF_MAX; +const SMALL_EXP_RANGE: RangeInclusive<i32> = (-SMALL_EXP_MAX)..=SMALL_EXP_MAX; + +const LARGE_COEFF_RANGE: RangeInclusive<u32> = 0..=100_000; +const LARGE_EXP_RANGE: RangeInclusive<u32> = 300..=350; + +/// Check exponential values around zero. +pub struct SmallExponents<F: Float> { + iter: BoxGenIter<Self, F>, +} + +impl<F: Float> Generator<F> for SmallExponents<F> { + const NAME: &'static str = "small exponents"; + const SHORT_NAME: &'static str = "small exp"; + + /// `(coefficient, exponent)` + type WriteCtx = (i32, i32); + + fn total_tests() -> u64 { + ((1 + SMALL_COEFF_RANGE.end() - SMALL_COEFF_RANGE.start()) + * (1 + SMALL_EXP_RANGE.end() - SMALL_EXP_RANGE.start())) + .try_into() + .unwrap() + } + + fn new() -> Self { + let iter = SMALL_EXP_RANGE.flat_map(|exp| SMALL_COEFF_RANGE.map(move |coeff| (coeff, exp))); + + Self { iter: Box::new(iter) } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + let (coeff, exp) = ctx; + write!(s, "{coeff}e{exp}").unwrap(); + } +} + +impl<F: Float> Iterator for SmallExponents<F> { + type Item = (i32, i32); + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } +} + +/// Check exponential values further from zero. +pub struct LargeExponents<F: Float> { + iter: BoxGenIter<Self, F>, +} + +impl<F: Float> Generator<F> for LargeExponents<F> { + const NAME: &'static str = "large positive exponents"; + const SHORT_NAME: &'static str = "large exp"; + + /// `(coefficient, exponent, is_positive)` + type WriteCtx = (u32, u32, bool); + + fn total_tests() -> u64 { + ((1 + LARGE_EXP_RANGE.end() - LARGE_EXP_RANGE.start()) + * (1 + LARGE_COEFF_RANGE.end() - LARGE_COEFF_RANGE.start()) + * 2) + .into() + } + + fn new() -> Self { + let iter = LARGE_EXP_RANGE + .flat_map(|exp| LARGE_COEFF_RANGE.map(move |coeff| (coeff, exp))) + .flat_map(|(coeff, exp)| [(coeff, exp, false), (coeff, exp, true)]); + + Self { iter: Box::new(iter) } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + let (coeff, exp, is_positive) = ctx; + let sign = if is_positive { "" } else { "-" }; + write!(s, "{sign}{coeff}e{exp}").unwrap(); + } +} + +impl<F: Float> Iterator for LargeExponents<F> { + type Item = (u32, u32, bool); + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } +} diff --git a/src/etc/test-float-parse/src/gen/fuzz.rs b/src/etc/test-float-parse/src/gen/fuzz.rs new file mode 100644 index 00000000000..213bcfc64af --- /dev/null +++ b/src/etc/test-float-parse/src/gen/fuzz.rs @@ -0,0 +1,88 @@ +use std::any::{type_name, TypeId}; +use std::collections::BTreeMap; +use std::fmt::Write; +use std::marker::PhantomData; +use std::ops::Range; +use std::sync::Mutex; + +use rand::distributions::{Distribution, Standard}; +use rand::Rng; +use rand_chacha::rand_core::SeedableRng; +use rand_chacha::ChaCha8Rng; + +use crate::{Float, Generator, Int, SEED}; + +/// Mapping of float types to the number of iterations that should be run. +/// +/// We could probably make `Generator::new` take an argument instead of the global state, +/// but we only load this once so it works. +static FUZZ_COUNTS: Mutex<BTreeMap<TypeId, u64>> = Mutex::new(BTreeMap::new()); + +/// Generic fuzzer; just tests deterministic random bit patterns N times. +pub struct Fuzz<F> { + iter: Range<u64>, + rng: ChaCha8Rng, + /// Allow us to use generics in `Iterator`. + marker: PhantomData<F>, +} + +impl<F: Float> Fuzz<F> { + /// Register how many iterations the fuzzer should run for a type. Uses some logic by + /// default, but if `from_cfg` is `Some`, that will be used instead. + pub fn set_iterations(from_cfg: Option<u64>) { + let count = if let Some(cfg_count) = from_cfg { + cfg_count + } else if F::BITS <= crate::MAX_BITS_FOR_EXHAUUSTIVE { + // If we run exhaustively, still fuzz but only do half as many bits. The only goal here is + // to catch failures from e.g. high bit patterns before exhaustive tests would get to them. + (F::Int::MAX >> (F::BITS / 2)).try_into().unwrap() + } else { + // Eveything bigger gets a fuzz test with as many iterations as `f32` exhaustive. + u32::MAX.into() + }; + + let _ = FUZZ_COUNTS.lock().unwrap().insert(TypeId::of::<F>(), count); + } +} + +impl<F: Float> Generator<F> for Fuzz<F> +where + Standard: Distribution<<F as Float>::Int>, +{ + const NAME: &'static str = "fuzz"; + const SHORT_NAME: &'static str = "fuzz"; + + type WriteCtx = F; + + fn total_tests() -> u64 { + *FUZZ_COUNTS + .lock() + .unwrap() + .get(&TypeId::of::<F>()) + .unwrap_or_else(|| panic!("missing fuzz count for {}", type_name::<F>())) + } + + fn new() -> Self { + let rng = ChaCha8Rng::from_seed(SEED); + + Self { iter: 0..Self::total_tests(), rng, marker: PhantomData } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl<F: Float> Iterator for Fuzz<F> +where + Standard: Distribution<<F as Float>::Int>, +{ + type Item = <Self as Generator<F>>::WriteCtx; + + fn next(&mut self) -> Option<Self::Item> { + let _ = self.iter.next()?; + let i: F::Int = self.rng.gen(); + + Some(F::from_bits(i)) + } +} diff --git a/src/etc/test-float-parse/src/gen/integers.rs b/src/etc/test-float-parse/src/gen/integers.rs new file mode 100644 index 00000000000..070d188e88c --- /dev/null +++ b/src/etc/test-float-parse/src/gen/integers.rs @@ -0,0 +1,104 @@ +use std::fmt::Write; +use std::ops::{Range, RangeInclusive}; + +use crate::traits::BoxGenIter; +use crate::{Float, Generator}; + +const SMALL_MAX_POW2: u32 = 19; + +/// All values up to the max power of two +const SMALL_VALUES: RangeInclusive<i32> = { + let max = 1i32 << SMALL_MAX_POW2; + (-max)..=max +}; + +/// Large values only get tested around powers of two +const LARGE_POWERS: Range<u32> = SMALL_MAX_POW2..128; + +/// We perturbe each large value around these ranges +const LARGE_PERTURBATIONS: RangeInclusive<i128> = -256..=256; + +/// Test all integers up to `2 ^ MAX_POW2` +pub struct SmallInt { + iter: RangeInclusive<i32>, +} + +impl<F: Float> Generator<F> for SmallInt { + const NAME: &'static str = "small integer values"; + const SHORT_NAME: &'static str = "int small"; + + type WriteCtx = i32; + + fn total_tests() -> u64 { + (SMALL_VALUES.end() + 1 - SMALL_VALUES.start()).try_into().unwrap() + } + + fn new() -> Self { + Self { iter: SMALL_VALUES } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx}").unwrap(); + } +} + +impl Iterator for SmallInt { + type Item = i32; + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } +} + +/// Test much bigger integers than [`SmallInt`]. +pub struct LargeInt<F: Float> { + iter: BoxGenIter<Self, F>, +} + +impl<F: Float> LargeInt<F> { + const EDGE_CASES: [i128; 7] = [ + i32::MIN as i128, + i32::MAX as i128, + i64::MIN as i128, + i64::MAX as i128, + u64::MAX as i128, + i128::MIN, + i128::MAX, + ]; +} + +impl<F: Float> Generator<F> for LargeInt<F> { + const NAME: &'static str = "large integer values"; + const SHORT_NAME: &'static str = "int large"; + + type WriteCtx = i128; + + fn total_tests() -> u64 { + u64::try_from( + (i128::from(LARGE_POWERS.end - LARGE_POWERS.start) + + i128::try_from(Self::EDGE_CASES.len()).unwrap()) + * (LARGE_PERTURBATIONS.end() + 1 - LARGE_PERTURBATIONS.start()), + ) + .unwrap() + } + + fn new() -> Self { + let iter = LARGE_POWERS + .map(|pow| 1i128 << pow) + .chain(Self::EDGE_CASES) + .flat_map(|base| LARGE_PERTURBATIONS.map(move |perturb| base.saturating_add(perturb))); + + Self { iter: Box::new(iter) } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx}").unwrap(); + } +} +impl<F: Float> Iterator for LargeInt<F> { + type Item = i128; + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } +} diff --git a/src/etc/test-float-parse/src/gen/long_fractions.rs b/src/etc/test-float-parse/src/gen/long_fractions.rs new file mode 100644 index 00000000000..b75148b779c --- /dev/null +++ b/src/etc/test-float-parse/src/gen/long_fractions.rs @@ -0,0 +1,58 @@ +use std::char; +use std::fmt::Write; + +use crate::{Float, Generator}; + +/// Number of decimal digits to check (all of them). +const MAX_DIGIT: u32 = 9; +/// Test with this many decimals in the string. +const MAX_DECIMALS: usize = 410; +const PREFIX: &str = "0."; + +/// Test e.g. `0.1`, `0.11`, `0.111`, `0.1111`, ..., `0.2`, `0.22`, ... +pub struct RepeatingDecimal { + digit: u32, + buf: String, +} + +impl<F: Float> Generator<F> for RepeatingDecimal { + const NAME: &'static str = "repeating decimal"; + const SHORT_NAME: &'static str = "dec rep"; + + type WriteCtx = String; + + fn total_tests() -> u64 { + u64::from(MAX_DIGIT + 1) * u64::try_from(MAX_DECIMALS + 1).unwrap() + 1 + } + + fn new() -> Self { + Self { digit: 0, buf: PREFIX.to_owned() } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + *s = ctx; + } +} + +impl Iterator for RepeatingDecimal { + type Item = String; + + fn next(&mut self) -> Option<Self::Item> { + if self.digit > MAX_DIGIT { + return None; + } + + let digit = self.digit; + let inc_digit = self.buf.len() - PREFIX.len() > MAX_DECIMALS; + + if inc_digit { + // Reset the string + self.buf.clear(); + self.digit += 1; + self.buf.write_str(PREFIX).unwrap(); + } + + self.buf.push(char::from_digit(digit, 10).unwrap()); + Some(self.buf.clone()) + } +} diff --git a/src/etc/test-float-parse/src/gen/many_digits.rs b/src/etc/test-float-parse/src/gen/many_digits.rs new file mode 100644 index 00000000000..aab8d5d704b --- /dev/null +++ b/src/etc/test-float-parse/src/gen/many_digits.rs @@ -0,0 +1,84 @@ +use std::char; +use std::fmt::Write; +use std::marker::PhantomData; +use std::ops::{Range, RangeInclusive}; + +use rand::distributions::{Distribution, Uniform}; +use rand::{Rng, SeedableRng}; +use rand_chacha::ChaCha8Rng; + +use crate::{Float, Generator, SEED}; + +/// Total iterations +const ITERATIONS: u64 = 5_000_000; + +/// Possible lengths of the string, excluding decimals and exponents +const POSSIBLE_NUM_DIGITS: RangeInclusive<usize> = 100..=400; + +/// Range of possible exponents +const EXP_RANGE: Range<i32> = -4500..4500; + +/// Try strings of random digits. +pub struct RandDigits<F> { + rng: ChaCha8Rng, + iter: Range<u64>, + uniform: Uniform<u32>, + /// Allow us to use generics in `Iterator`. + marker: PhantomData<F>, +} + +impl<F: Float> Generator<F> for RandDigits<F> { + const NAME: &'static str = "random digits"; + + const SHORT_NAME: &'static str = "rand digits"; + + type WriteCtx = String; + + fn total_tests() -> u64 { + ITERATIONS + } + + fn new() -> Self { + let rng = ChaCha8Rng::from_seed(SEED); + let range = Uniform::from(0..10); + + Self { rng, iter: 0..ITERATIONS, uniform: range, marker: PhantomData } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + *s = ctx; + } +} + +impl<F: Float> Iterator for RandDigits<F> { + type Item = String; + + fn next(&mut self) -> Option<Self::Item> { + let _ = self.iter.next()?; + let num_digits = self.rng.gen_range(POSSIBLE_NUM_DIGITS); + let has_decimal = self.rng.gen_bool(0.2); + let has_exp = self.rng.gen_bool(0.2); + + let dec_pos = if has_decimal { Some(self.rng.gen_range(0..num_digits)) } else { None }; + + let mut s = String::with_capacity(num_digits); + + for pos in 0..num_digits { + let digit = char::from_digit(self.uniform.sample(&mut self.rng), 10).unwrap(); + s.push(digit); + + if let Some(dec_pos) = dec_pos { + if pos == dec_pos { + s.push('.'); + } + } + } + + if has_exp { + let exp = self.rng.gen_range(EXP_RANGE); + write!(s, "e{exp}").unwrap(); + } + + Some(s) + } +} diff --git a/src/etc/test-float-parse/src/gen/sparse.rs b/src/etc/test-float-parse/src/gen/sparse.rs new file mode 100644 index 00000000000..389b71056a3 --- /dev/null +++ b/src/etc/test-float-parse/src/gen/sparse.rs @@ -0,0 +1,100 @@ +use std::fmt::Write; + +use crate::traits::BoxGenIter; +use crate::{Float, Generator}; + +const POWERS_OF_TWO: [u128; 128] = make_powers_of_two(); + +const fn make_powers_of_two() -> [u128; 128] { + let mut ret = [0; 128]; + let mut i = 0; + while i < 128 { + ret[i] = 1 << i; + i += 1; + } + + ret +} + +/// Can't clone this result because of lifetime errors, just use a macro. +macro_rules! pow_iter { + () => { + (0..F::BITS).map(|i| F::Int::try_from(POWERS_OF_TWO[i as usize]).unwrap()) + }; +} + +/// Test all numbers that include three 1s in the binary representation as integers. +pub struct FewOnesInt<F: Float> +where + FewOnesInt<F>: Generator<F>, +{ + iter: BoxGenIter<Self, F>, +} + +impl<F: Float> Generator<F> for FewOnesInt<F> +where + <F::Int as TryFrom<u128>>::Error: std::fmt::Debug, +{ + const NAME: &'static str = "few ones int"; + const SHORT_NAME: &'static str = "few ones int"; + + type WriteCtx = F::Int; + + fn total_tests() -> u64 { + u64::from(F::BITS).pow(3) + } + + fn new() -> Self { + let iter = pow_iter!() + .flat_map(move |a| pow_iter!().map(move |b| (a, b))) + .flat_map(move |(a, b)| pow_iter!().map(move |c| (a, b, c))) + .map(|(a, b, c)| a | b | c); + + Self { iter: Box::new(iter) } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx}").unwrap(); + } +} + +impl<F: Float> Iterator for FewOnesInt<F> { + type Item = F::Int; + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next() + } +} + +/// Similar to `FewOnesInt` except test those bit patterns as a float. +pub struct FewOnesFloat<F: Float>(FewOnesInt<F>); + +impl<F: Float> Generator<F> for FewOnesFloat<F> +where + <F::Int as TryFrom<u128>>::Error: std::fmt::Debug, +{ + const NAME: &'static str = "few ones float"; + const SHORT_NAME: &'static str = "few ones float"; + + type WriteCtx = F; + + fn total_tests() -> u64 { + FewOnesInt::<F>::total_tests() + } + + fn new() -> Self { + Self(FewOnesInt::new()) + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl<F: Float> Iterator for FewOnesFloat<F> { + type Item = F; + + fn next(&mut self) -> Option<Self::Item> { + self.0.next().map(|i| F::from_bits(i)) + } +} diff --git a/src/etc/test-float-parse/src/gen/spot_checks.rs b/src/etc/test-float-parse/src/gen/spot_checks.rs new file mode 100644 index 00000000000..18691f9d6cf --- /dev/null +++ b/src/etc/test-float-parse/src/gen/spot_checks.rs @@ -0,0 +1,101 @@ +use std::fmt::Write; + +use crate::traits::{Float, Generator}; + +const SPECIAL: &[&str] = &[ + "inf", "Inf", "iNf", "INF", "-inf", "-Inf", "-iNf", "-INF", "+inf", "+Inf", "+iNf", "+INF", + "nan", "NaN", "NAN", "nAn", "-nan", "-NaN", "-NAN", "-nAn", "+nan", "+NaN", "+NAN", "+nAn", + "1", "-1", "+1", "1e1", "-1e1", "+1e1", "1e-1", "-1e-1", "+1e-1", "1e+1", "-1e+1", "+1e+1", + "1E1", "-1E1", "+1E1", "1E-1", "-1E-1", "+1E-1", "1E+1", "-1E+1", "+1E+1", "0", "-0", "+0", +]; + +/// Check various non-numeric special strings. +pub struct Special { + iter: std::slice::Iter<'static, &'static str>, +} + +impl<F: Float> Generator<F> for Special { + const NAME: &'static str = "special values"; + + const SHORT_NAME: &'static str = "special"; + + type WriteCtx = &'static str; + + fn total_tests() -> u64 { + SPECIAL.len().try_into().unwrap() + } + + fn new() -> Self { + Self { iter: SPECIAL.iter() } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + s.write_str(ctx).unwrap(); + } +} + +impl Iterator for Special { + type Item = &'static str; + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().copied() + } +} + +/// Strings that we know have failed in the past +const REGRESSIONS: &[&str] = &[ + // From <https://github.com/rust-lang/rust/issues/31407> + "1234567890123456789012345678901234567890e-340", + "2.225073858507201136057409796709131975934819546351645648023426109724822222021076945516529523908135087914149158913039621106870086438694594645527657207407820621743379988141063267329253552286881372149012981122451451889849057222307285255133155755015914397476397983411801999323962548289017107081850690630666655994938275772572015763062690663332647565300009245888316433037779791869612049497390377829704905051080609940730262937128958950003583799967207254304360284078895771796150945516748243471030702609144621572289880258182545180325707018860872113128079512233426288368622321503775666622503982534335974568884423900265498198385487948292206894721689831099698365846814022854243330660339850886445804001034933970427567186443383770486037861622771738545623065874679014086723327636718749999999999999999999999999999999999999e-308", + "2.22507385850720113605740979670913197593481954635164564802342610972482222202107694551652952390813508791414915891303962110687008643869459464552765720740782062174337998814106326732925355228688137214901298112245145188984905722230728525513315575501591439747639798341180199932396254828901710708185069063066665599493827577257201576306269066333264756530000924588831643303777979186961204949739037782970490505108060994073026293712895895000358379996720725430436028407889577179615094551674824347103070260914462157228988025818254518032570701886087211312807951223342628836862232150377566662250398253433597456888442390026549819838548794829220689472168983109969836584681402285424333066033985088644580400103493397042756718644338377048603786162277173854562306587467901408672332763671875e-308", + "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000222507385850720138309023271733240406421921598046233183055332741688720443481391819585428315901251102056406733973103581100515243416155346010885601238537771882113077799353200233047961014744258363607192156504694250373420837525080665061665815894872049117996859163964850063590877011830487479978088775374994945158045160505091539985658247081864511353793580499211598108576605199243335211435239014879569960959128889160299264151106346631339366347758651302937176204732563178148566435087212282863764204484681140761391147706280168985324411002416144742161856716615054015428508471675290190316132277889672970737312333408698898317506783884692609277397797285865965494109136909540613646756870239867831529068098461721092462539672851562500000000000000001", + "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.9999999999999999999999999999999999999999999999999999999999999999999999", + "2.47032822920623272e-324", + "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125E-316", + "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875E-319", + "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125E-310", + "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875E-319", + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328124999e-324", + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125e-324", + "2.4703282292062327208828439643411068618252990130716238221279284125033775363510437593264991818081799618989828234772285886546332835517796989819938739800539093906315035659515570226392290858392449105184435931802849936536152500319370457678249219365623669863658480757001585769269903706311928279558551332927834338409351978015531246597263579574622766465272827220056374006485499977096599470454020828166226237857393450736339007967761930577506740176324673600968951340535537458516661134223766678604162159680461914467291840300530057530849048765391711386591646239524912623653881879636239373280423891018672348497668235089863388587925628302755995657524455507255189313690836254779186948667994968324049705821028513185451396213837722826145437693412532098591327667236328125001e-324", + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984374999e-324", + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375e-324", + "7.4109846876186981626485318930233205854758970392148714663837852375101326090531312779794975454245398856969484704316857659638998506553390969459816219401617281718945106978546710679176872575177347315553307795408549809608457500958111373034747658096871009590975442271004757307809711118935784838675653998783503015228055934046593739791790738723868299395818481660169122019456499931289798411362062484498678713572180352209017023903285791732520220528974020802906854021606612375549983402671300035812486479041385743401875520901590172592547146296175134159774938718574737870961645638908718119841271673056017045493004705269590165763776884908267986972573366521765567941072508764337560846003984904972149117463085539556354188641513168478436313080237596295773983001708984375001e-324", + "94393431193180696942841837085033647913224148539854e-358", + "104308485241983990666713401708072175773165034278685682646111762292409330928739751702404658197872319129036519947435319418387839758990478549477777586673075945844895981012024387992135617064532141489278815239849108105951619997829153633535314849999674266169258928940692239684771590065027025835804863585454872499320500023126142553932654370362024104462255244034053203998964360882487378334860197725139151265590832887433736189468858614521708567646743455601905935595381852723723645799866672558576993978025033590728687206296379801363024094048327273913079612469982585674824156000783167963081616214710691759864332339239688734656548790656486646106983450809073750535624894296242072010195710276073042036425579852459556183541199012652571123898996574563824424330960027873516082763671875e-1075", + "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281249", + "0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000247032822920623272088284396434110686182529901307162382212792841250337753635104375932649918180817996189898282347722858865463328355177969898199387398005390939063150356595155702263922908583924491051844359318028499365361525003193704576782492193656236698636584807570015857692699037063119282795585513329278343384093519780155312465972635795746227664652728272200563740064854999770965994704540208281662262378573934507363390079677619305775067401763246736009689513405355374585166611342237666786041621596804619144672918403005300575308490487653917113865916462395249126236538818796362393732804238910186723484976682350898633885879256283027559956575244555072551893136908362547791869486679949683240497058210285131854513962138377228261454376934125320985913276672363281251", +]; + +/// Check items that failed in the past. +pub struct RegressionCheck { + iter: std::slice::Iter<'static, &'static str>, +} + +impl<F: Float> Generator<F> for RegressionCheck { + const NAME: &'static str = "regression check"; + + const SHORT_NAME: &'static str = "regression"; + + type WriteCtx = &'static str; + + fn total_tests() -> u64 { + REGRESSIONS.len().try_into().unwrap() + } + + fn new() -> Self { + Self { iter: REGRESSIONS.iter() } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + s.write_str(ctx).unwrap(); + } +} + +impl Iterator for RegressionCheck { + type Item = &'static str; + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().copied() + } +} diff --git a/src/etc/test-float-parse/src/gen/subnorm.rs b/src/etc/test-float-parse/src/gen/subnorm.rs new file mode 100644 index 00000000000..4fe3b90a3dd --- /dev/null +++ b/src/etc/test-float-parse/src/gen/subnorm.rs @@ -0,0 +1,103 @@ +use std::cmp::min; +use std::fmt::Write; +use std::ops::RangeInclusive; + +use crate::{Float, Generator, Int}; + +/// Spot check some edge cases for subnormals. +pub struct SubnormEdgeCases<F: Float> { + cases: [F::Int; 6], + index: usize, +} + +impl<F: Float> SubnormEdgeCases<F> { + /// Shorthand + const I1: F::Int = F::Int::ONE; + + fn edge_cases() -> [F::Int; 6] { + // Comments use an 8-bit mantissa as a demo + [ + // 0b00000001 + Self::I1, + // 0b10000000 + Self::I1 << (F::MAN_BITS - 1), + // 0b00001000 + Self::I1 << ((F::MAN_BITS / 2) - 1), + // 0b00001111 + Self::I1 << ((F::MAN_BITS / 2) - 1), + // 0b00001111 + Self::I1 << ((F::MAN_BITS / 2) - 1), + // 0b11111111 + F::MAN_MASK, + ] + } +} + +impl<F: Float> Generator<F> for SubnormEdgeCases<F> { + const NAME: &'static str = "subnormal edge cases"; + const SHORT_NAME: &'static str = "subnorm edge"; + + type WriteCtx = F; + + fn new() -> Self { + Self { cases: Self::edge_cases(), index: 0 } + } + + fn total_tests() -> u64 { + Self::edge_cases().len().try_into().unwrap() + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl<F: Float> Iterator for SubnormEdgeCases<F> { + type Item = F; + + fn next(&mut self) -> Option<Self::Item> { + let i = self.cases.get(self.index)?; + self.index += 1; + + Some(F::from_bits(*i)) + } +} + +/// Test all subnormals up to `1 << 22`. +pub struct SubnormComplete<F: Float> { + iter: RangeInclusive<F::Int>, +} + +impl<F: Float> Generator<F> for SubnormComplete<F> +where + RangeInclusive<F::Int>: Iterator<Item = F::Int>, +{ + const NAME: &'static str = "subnormal"; + const SHORT_NAME: &'static str = "subnorm "; + + type WriteCtx = F; + + fn total_tests() -> u64 { + let iter = Self::new().iter; + (F::Int::ONE + *iter.end() - *iter.start()).try_into().unwrap() + } + + fn new() -> Self { + Self { iter: F::Int::ZERO..=min(F::Int::ONE << 22, F::MAN_BITS.try_into().unwrap()) } + } + + fn write_string(s: &mut String, ctx: Self::WriteCtx) { + write!(s, "{ctx:e}").unwrap(); + } +} + +impl<F: Float> Iterator for SubnormComplete<F> +where + RangeInclusive<F::Int>: Iterator<Item = F::Int>, +{ + type Item = F; + + fn next(&mut self) -> Option<Self::Item> { + Some(F::from_bits(self.iter.next()?)) + } +} diff --git a/src/etc/test-float-parse/src/lib.rs b/src/etc/test-float-parse/src/lib.rs index 9cbad5486b4..f36e3928d26 100644 --- a/src/etc/test-float-parse/src/lib.rs +++ b/src/etc/test-float-parse/src/lib.rs @@ -1,16 +1,526 @@ -use std::io; -use std::io::prelude::*; -use std::mem::transmute; - -// Nothing up my sleeve: Just (PI - 3) in base 16. -#[allow(dead_code)] -pub const SEED: [u32; 3] = [0x243f_6a88, 0x85a3_08d3, 0x1319_8a2e]; - -pub fn validate(text: &str) { - let mut out = io::stdout(); - let x: f64 = text.parse().unwrap(); - let f64_bytes: u64 = unsafe { transmute(x) }; - let x: f32 = text.parse().unwrap(); - let f32_bytes: u32 = unsafe { transmute(x) }; - writeln!(&mut out, "{:016x} {:08x} {}", f64_bytes, f32_bytes, text).unwrap(); +mod traits; +mod ui; +mod validate; + +use std::any::{type_name, TypeId}; +use std::cmp::min; +use std::ops::RangeInclusive; +use std::process::ExitCode; +use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::{mpsc, OnceLock}; +use std::{fmt, time}; + +use indicatif::{MultiProgress, ProgressBar}; +use rand::distributions::{Distribution, Standard}; +use rayon::prelude::*; +use time::{Duration, Instant}; +use traits::{Float, Generator, Int}; + +/// Test generators. +mod gen { + pub mod exhaustive; + pub mod exponents; + pub mod fuzz; + pub mod integers; + pub mod long_fractions; + pub mod many_digits; + pub mod sparse; + pub mod spot_checks; + pub mod subnorm; +} + +/// How many failures to exit after if unspecified. +const DEFAULT_MAX_FAILURES: u64 = 20; + +/// Register exhaustive tests only for <= 32 bits. No more because it would take years. +const MAX_BITS_FOR_EXHAUUSTIVE: u32 = 32; + +/// If there are more tests than this threashold, the test will be defered until after all +/// others run (so as to avoid thread pool starvation). They also can be excluded with +/// `--skip-huge`. +const HUGE_TEST_CUTOFF: u64 = 5_000_000; + +/// Seed for tests that use a deterministic RNG. +const SEED: [u8; 32] = *b"3.141592653589793238462643383279"; + +/// Global configuration +#[derive(Debug)] +pub struct Config { + pub timeout: Duration, + /// Failures per test + pub max_failures: u64, + pub disable_max_failures: bool, + /// If `None`, the default will be used + pub fuzz_count: Option<u64>, + pub skip_huge: bool, +} + +impl Default for Config { + fn default() -> Self { + Self { + timeout: Duration::from_secs(60 * 60 * 3), + max_failures: DEFAULT_MAX_FAILURES, + disable_max_failures: false, + fuzz_count: None, + skip_huge: false, + } + } +} + +/// Collect, filter, and launch all tests. +pub fn run(cfg: Config, include: &[String], exclude: &[String]) -> ExitCode { + // With default parallelism, the CPU doesn't saturate. We don't need to be nice to + // other processes, so do 1.5x to make sure we use all available resources. + let threads = std::thread::available_parallelism().map(Into::into).unwrap_or(0) * 3 / 2; + rayon::ThreadPoolBuilder::new().num_threads(threads).build_global().unwrap(); + + let mut tests = register_tests(&cfg); + println!("registered"); + let initial_tests: Vec<_> = tests.iter().map(|t| t.name.clone()).collect(); + + let unmatched: Vec<_> = include + .iter() + .chain(exclude.iter()) + .filter(|filt| !tests.iter().any(|t| t.matches(filt))) + .collect(); + + assert!( + unmatched.is_empty(), + "filters were provided that have no matching tests: {unmatched:#?}" + ); + + tests.retain(|test| !exclude.iter().any(|exc| test.matches(exc))); + + if cfg.skip_huge { + tests.retain(|test| !test.is_huge_test()); + } + + if !include.is_empty() { + tests.retain(|test| include.iter().any(|inc| test.matches(inc))); + } + + for exc in initial_tests.iter().filter(|orig_name| !tests.iter().any(|t| t.name == **orig_name)) + { + println!("Skipping test '{exc}'"); + } + + println!("launching"); + let elapsed = launch_tests(&mut tests, &cfg); + ui::finish(&tests, elapsed, &cfg) +} + +/// Enumerate tests to run but don't actaully run them. +pub fn register_tests(cfg: &Config) -> Vec<TestInfo> { + let mut tests = Vec::new(); + + // Register normal generators for all floats. + register_float::<f32>(&mut tests, cfg); + register_float::<f64>(&mut tests, cfg); + + tests.sort_unstable_by_key(|t| (t.float_name, t.gen_name)); + for i in 0..(tests.len() - 1) { + if tests[i].gen_name == tests[i + 1].gen_name { + panic!("dupliate test name {}", tests[i].gen_name); + } + } + + tests +} + +/// Register all generators for a single float. +fn register_float<F: Float>(tests: &mut Vec<TestInfo>, cfg: &Config) +where + RangeInclusive<F::Int>: Iterator<Item = F::Int>, + <F::Int as TryFrom<u128>>::Error: std::fmt::Debug, + Standard: Distribution<<F as traits::Float>::Int>, +{ + if F::BITS <= MAX_BITS_FOR_EXHAUUSTIVE { + // Only run exhaustive tests if there is a chance of completion. + TestInfo::register::<F, gen::exhaustive::Exhaustive<F>>(tests); + } + + gen::fuzz::Fuzz::<F>::set_iterations(cfg.fuzz_count); + + TestInfo::register::<F, gen::exponents::LargeExponents<F>>(tests); + TestInfo::register::<F, gen::exponents::SmallExponents<F>>(tests); + TestInfo::register::<F, gen::fuzz::Fuzz<F>>(tests); + TestInfo::register::<F, gen::integers::LargeInt<F>>(tests); + TestInfo::register::<F, gen::integers::SmallInt>(tests); + TestInfo::register::<F, gen::long_fractions::RepeatingDecimal>(tests); + TestInfo::register::<F, gen::many_digits::RandDigits<F>>(tests); + TestInfo::register::<F, gen::sparse::FewOnesFloat<F>>(tests); + TestInfo::register::<F, gen::sparse::FewOnesInt<F>>(tests); + TestInfo::register::<F, gen::spot_checks::RegressionCheck>(tests); + TestInfo::register::<F, gen::spot_checks::Special>(tests); + TestInfo::register::<F, gen::subnorm::SubnormComplete<F>>(tests); + TestInfo::register::<F, gen::subnorm::SubnormEdgeCases<F>>(tests); +} + +/// Configuration for a single test. +#[derive(Debug)] +pub struct TestInfo { + pub name: String, + /// Tests are identified by the type ID of `(F, G)` (tuple of the float and generator type). + /// This gives an easy way to associate messages with tests. + id: TypeId, + float_name: &'static str, + gen_name: &'static str, + /// Name for display in the progress bar. + short_name: String, + total_tests: u64, + /// Function to launch this test. + launch: fn(&mpsc::Sender<Msg>, &TestInfo, &Config), + /// Progress bar to be updated. + pb: Option<ProgressBar>, + /// Once completed, this will be set. + completed: OnceLock<Completed>, +} + +impl TestInfo { + /// Check if either the name or short name is a match, for filtering. + fn matches(&self, pat: &str) -> bool { + self.short_name.contains(pat) || self.name.contains(pat) + } + + /// Create a `TestInfo` for a given float and generator, then add it to a list. + fn register<F: Float, G: Generator<F>>(v: &mut Vec<Self>) { + let f_name = type_name::<F>(); + let gen_name = G::NAME; + let gen_short_name = G::SHORT_NAME; + + let info = TestInfo { + id: TypeId::of::<(F, G)>(), + float_name: f_name, + gen_name, + pb: None, + name: format!("{f_name} {gen_name}"), + short_name: format!("{f_name} {gen_short_name}"), + launch: test_runner::<F, G>, + total_tests: G::total_tests(), + completed: OnceLock::new(), + }; + v.push(info); + } + + /// Pad the short name to a common width for progress bar use. + fn short_name_padded(&self) -> String { + format!("{:18}", self.short_name) + } + + /// Create a progress bar for this test within a multiprogress bar. + fn register_pb(&mut self, mp: &MultiProgress, drop_bars: &mut Vec<ProgressBar>) { + self.pb = Some(ui::create_pb(mp, self.total_tests, &self.short_name_padded(), drop_bars)); + } + + /// When the test is finished, update progress bar messages and finalize. + fn finalize_pb(&self, c: &Completed) { + let pb = self.pb.as_ref().unwrap(); + ui::finalize_pb(pb, &self.short_name_padded(), c); + } + + /// True if this should be run after all others. + fn is_huge_test(&self) -> bool { + self.total_tests >= HUGE_TEST_CUTOFF + } +} + +/// A message sent from test runner threads to the UI/log thread. +#[derive(Clone, Debug)] +struct Msg { + id: TypeId, + update: Update, +} + +impl Msg { + /// Wrap an `Update` into a message for the specified type. We use the `TypeId` of `(F, G)` to + /// identify which test a message in the channel came from. + fn new<F: Float, G: Generator<F>>(u: Update) -> Self { + Self { id: TypeId::of::<(F, G)>(), update: u } + } + + /// Get the matching test from a list. Panics if not found. + fn find_test<'a>(&self, tests: &'a [TestInfo]) -> &'a TestInfo { + tests.iter().find(|t| t.id == self.id).unwrap() + } + + /// Update UI as needed for a single message received from the test runners. + fn handle(self, tests: &[TestInfo], mp: &MultiProgress) { + let test = self.find_test(tests); + let pb = test.pb.as_ref().unwrap(); + + match self.update { + Update::Started => { + mp.println(format!("Testing '{}'", test.name)).unwrap(); + } + Update::Progress { executed, failures } => { + pb.set_message(format! {"{failures}"}); + pb.set_position(executed); + } + Update::Failure { fail, input, float_res } => { + mp.println(format!( + "Failure in '{}': {fail}. parsing '{input}'. Parsed as: {float_res}", + test.name + )) + .unwrap(); + } + Update::Completed(c) => { + test.finalize_pb(&c); + + let prefix = match c.result { + Ok(FinishedAll) => "Completed tests for", + Err(EarlyExit::Timeout) => "Timed out", + Err(EarlyExit::MaxFailures) => "Max failures reached for", + }; + + mp.println(format!( + "{prefix} generator '{}' in {:?}. {} tests run, {} failures", + test.name, c.elapsed, c.executed, c.failures + )) + .unwrap(); + test.completed.set(c).unwrap(); + } + }; + } +} + +/// Status sent with a message. +#[derive(Clone, Debug)] +enum Update { + /// Starting a new test runner. + Started, + /// Completed a out of b tests. + Progress { executed: u64, failures: u64 }, + /// Received a failed test. + Failure { + fail: CheckFailure, + /// String for which parsing was attempted. + input: Box<str>, + /// The parsed & decomposed `FloatRes`, aleady stringified so we don't need generics here. + float_res: Box<str>, + }, + /// Exited with an unexpected condition. + Completed(Completed), +} + +/// Result of an input did not parsing successfully. +#[derive(Clone, Debug)] +enum CheckFailure { + /// Above the zero cutoff but got rounded to zero. + UnexpectedZero, + /// Below the infinity cutoff but got rounded to infinity. + UnexpectedInf, + /// Above the negative infinity cutoff but got rounded to negative infinity. + UnexpectedNegInf, + /// Got a `NaN` when none was expected. + UnexpectedNan, + /// Expected `NaN`, got none. + ExpectedNan, + /// Expected infinity, got finite. + ExpectedInf, + /// Expected negative infinity, got finite. + ExpectedNegInf, + /// The value exceeded its error tolerance. + InvalidReal { + /// Error from the expected value, as a float. + error_float: Option<f64>, + /// Error as a rational string (since it can't always be represented as a float). + error_str: Box<str>, + /// True if the error was caused by not rounding to even at the midpoint between + /// two representable values. + incorrect_midpoint_rounding: bool, + }, +} + +impl fmt::Display for CheckFailure { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + CheckFailure::UnexpectedZero => { + write!(f, "incorrectly rounded to 0 (expected nonzero)") + } + CheckFailure::UnexpectedInf => { + write!(f, "incorrectly rounded to +inf (expected finite)") + } + CheckFailure::UnexpectedNegInf => { + write!(f, "incorrectly rounded to -inf (expected finite)") + } + CheckFailure::UnexpectedNan => write!(f, "got a NaN where none was expected"), + CheckFailure::ExpectedNan => write!(f, "expected a NaN but did not get it"), + CheckFailure::ExpectedInf => write!(f, "expected +inf but did not get it"), + CheckFailure::ExpectedNegInf => write!(f, "expected -inf but did not get it"), + CheckFailure::InvalidReal { error_float, error_str, incorrect_midpoint_rounding } => { + if *incorrect_midpoint_rounding { + write!( + f, + "midpoint between two representable values did not correctly \ + round to even; error: {error_str}" + )?; + } else { + write!(f, "real number did not parse correctly; error: {error_str}")?; + } + + if let Some(float) = error_float { + write!(f, " ({float})")?; + } + Ok(()) + } + } + } +} + +/// Information about a completed test generator. +#[derive(Clone, Debug)] +struct Completed { + /// Finished tests (both successful and failed). + executed: u64, + /// Failed tests. + failures: u64, + /// Extra exit information if unsuccessful. + result: Result<FinishedAll, EarlyExit>, + /// If there is something to warn about (e.g bad estimate), leave it here. + warning: Option<Box<str>>, + /// Total time to run the test. + elapsed: Duration, +} + +/// Marker for completing all tests (used in `Result` types). +#[derive(Clone, Debug)] +struct FinishedAll; + +/// Reasons for exiting early. +#[derive(Clone, Debug)] +enum EarlyExit { + Timeout, + MaxFailures, +} + +/// Run all tests in `tests`. +/// +/// This launches a main thread that receives messages and handlees UI updates, and uses the +/// rest of the thread pool to execute the tests. +fn launch_tests(tests: &mut [TestInfo], cfg: &Config) -> Duration { + // Run shorter tests first + tests.sort_unstable_by_key(|test| test.total_tests); + + for test in tests.iter() { + println!("Launching test '{}'", test.name); + } + + // Configure progress bars + let mut all_progress_bars = Vec::new(); + let mp = MultiProgress::new(); + mp.set_move_cursor(true); + for test in tests.iter_mut() { + test.register_pb(&mp, &mut all_progress_bars); + } + + ui::set_panic_hook(all_progress_bars); + + let (tx, rx) = mpsc::channel::<Msg>(); + let start = Instant::now(); + + rayon::scope(|scope| { + // Thread that updates the UI + scope.spawn(|_scope| { + let rx = rx; // move rx + + loop { + if tests.iter().all(|t| t.completed.get().is_some()) { + break; + } + + let msg = rx.recv().unwrap(); + msg.handle(tests, &mp); + } + + // All tests completed; finish things up + drop(mp); + assert_eq!(rx.try_recv().unwrap_err(), mpsc::TryRecvError::Empty); + }); + + // Don't let the thread pool be starved by huge tests. Run faster tests first in parallel, + // then parallelize only within the rest of the tests. + let (huge_tests, normal_tests): (Vec<_>, Vec<_>) = + tests.iter().partition(|t| t.is_huge_test()); + + // Run the actual tests + normal_tests.par_iter().for_each(|test| ((test.launch)(&tx, test, cfg))); + + huge_tests.par_iter().for_each(|test| ((test.launch)(&tx, test, cfg))); + }); + + start.elapsed() +} + +/// Test runer for a single generator. +/// +/// This calls the generator's iterator multiple times (in parallel) and validates each output. +fn test_runner<F: Float, G: Generator<F>>(tx: &mpsc::Sender<Msg>, _info: &TestInfo, cfg: &Config) { + tx.send(Msg::new::<F, G>(Update::Started)).unwrap(); + + let total = G::total_tests(); + let gen = G::new(); + let executed = AtomicU64::new(0); + let failures = AtomicU64::new(0); + + let checks_per_update = min(total, 1000); + let started = Instant::now(); + + // Function to execute for a single test iteration. + let check_one = |buf: &mut String, ctx: G::WriteCtx| { + let executed = executed.fetch_add(1, Ordering::Relaxed); + buf.clear(); + G::write_string(buf, ctx); + + match validate::validate::<F>(buf) { + Ok(()) => (), + Err(e) => { + tx.send(Msg::new::<F, G>(e)).unwrap(); + let f = failures.fetch_add(1, Ordering::Relaxed); + // End early if the limit is exceeded. + if f >= cfg.max_failures { + return Err(EarlyExit::MaxFailures); + } + } + }; + + // Send periodic updates + if executed % checks_per_update == 0 { + let failures = failures.load(Ordering::Relaxed); + + tx.send(Msg::new::<F, G>(Update::Progress { executed, failures })).unwrap(); + + if started.elapsed() > cfg.timeout { + return Err(EarlyExit::Timeout); + } + } + + Ok(()) + }; + + // Run the test iterations in parallel. Each thread gets a string buffer to write + // its check values to. + let res = gen.par_bridge().try_for_each_init(|| String::with_capacity(100), check_one); + + let elapsed = started.elapsed(); + let executed = executed.into_inner(); + let failures = failures.into_inner(); + + // Warn about bad estimates if relevant. + let warning = if executed != total && res.is_ok() { + let msg = format!("executed tests != estimated ({executed} != {total}) for {}", G::NAME); + + Some(msg.into()) + } else { + None + }; + + let result = res.map(|()| FinishedAll); + tx.send(Msg::new::<F, G>(Update::Completed(Completed { + executed, + failures, + result, + warning, + elapsed, + }))) + .unwrap(); } diff --git a/src/etc/test-float-parse/src/main.rs b/src/etc/test-float-parse/src/main.rs new file mode 100644 index 00000000000..9c6cad7324f --- /dev/null +++ b/src/etc/test-float-parse/src/main.rs @@ -0,0 +1,129 @@ +use std::process::ExitCode; +use std::time::Duration; + +use test_float_parse as tfp; + +static HELP: &str = r#"Usage: + + ./test-float-parse [--timeout x] [--exclude x] [--max-failures x] [INCLUDE ...] + ./test-float-parse [--fuzz-count x] [INCLUDE ...] + ./test-float-parse [--skip-huge] [INCLUDE ...] + ./test-float-parse --list + +Args: + + INCLUDE Include only tests with names containing these + strings. If this argument is not specified, all tests + are run. + --timeout N Exit after this amount of time (in seconds). + --exclude FILTER Skip tests containing this string. May be specified + more than once. + --list List available tests. + --max-failures N Limit to N failures per test. Defaults to 20. Pass + "--max-failures none" to remove this limit. + --fuzz-count N Run the fuzzer with N iterations. Only has an effect + if fuzz tests are enabled. Pass `--fuzz-count none` + to remove this limit. + --skip-huge Skip tests that run for a long time. + --all Reset previous `--exclude`, `--skip-huge`, and + `INCLUDE` arguments (useful for running all tests + via `./x`). +"#; + +enum ArgMode { + Any, + Timeout, + Exclude, + FuzzCount, + MaxFailures, +} + +fn main() -> ExitCode { + if cfg!(debug_assertions) { + println!( + "WARNING: running in debug mode. Release mode is recommended to reduce test duration." + ); + std::thread::sleep(Duration::from_secs(2)); + } + + let args: Vec<_> = std::env::args().skip(1).collect(); + if args.iter().any(|arg| arg == "--help" || arg == "-h") { + println!("{HELP}"); + return ExitCode::SUCCESS; + } + + if args.iter().any(|arg| arg == "--list") { + let tests = tfp::register_tests(&tfp::Config::default()); + println!("Available tests:"); + for t in tests { + println!("{}", t.name); + } + + return ExitCode::SUCCESS; + } + + let (cfg, include, exclude) = parse_args(args); + + tfp::run(cfg, &include, &exclude) +} + +/// Simple command argument parser +fn parse_args(args: Vec<String>) -> (tfp::Config, Vec<String>, Vec<String>) { + let mut cfg = tfp::Config::default(); + + let mut mode = ArgMode::Any; + let mut include = Vec::new(); + let mut exclude = Vec::new(); + + for arg in args { + mode = match mode { + ArgMode::Any if arg == "--timeout" => ArgMode::Timeout, + ArgMode::Any if arg == "--exclude" => ArgMode::Exclude, + ArgMode::Any if arg == "--max-failures" => ArgMode::MaxFailures, + ArgMode::Any if arg == "--fuzz-count" => ArgMode::FuzzCount, + ArgMode::Any if arg == "--skip-huge" => { + cfg.skip_huge = true; + ArgMode::Any + } + ArgMode::Any if arg == "--all" => { + cfg.skip_huge = false; + include.clear(); + exclude.clear(); + ArgMode::Any + } + ArgMode::Any if arg.starts_with('-') => { + panic!("Unknown argument {arg}. Usage:\n{HELP}") + } + ArgMode::Any => { + include.push(arg); + ArgMode::Any + } + ArgMode::Timeout => { + cfg.timeout = Duration::from_secs(arg.parse().unwrap()); + ArgMode::Any + } + ArgMode::MaxFailures => { + if arg == "none" { + cfg.disable_max_failures = true; + } else { + cfg.max_failures = arg.parse().unwrap(); + } + ArgMode::Any + } + ArgMode::FuzzCount => { + if arg == "none" { + cfg.fuzz_count = Some(u64::MAX); + } else { + cfg.fuzz_count = Some(arg.parse().unwrap()); + } + ArgMode::Any + } + ArgMode::Exclude => { + exclude.push(arg); + ArgMode::Any + } + } + } + + (cfg, include, exclude) +} diff --git a/src/etc/test-float-parse/src/traits.rs b/src/etc/test-float-parse/src/traits.rs new file mode 100644 index 00000000000..dc009ea235f --- /dev/null +++ b/src/etc/test-float-parse/src/traits.rs @@ -0,0 +1,202 @@ +//! Interfaces used throughout this crate. + +use std::str::FromStr; +use std::{fmt, ops}; + +use num::bigint::ToBigInt; +use num::Integer; + +use crate::validate::Constants; + +/// Integer types. +#[allow(dead_code)] // Some functions only used for testing +pub trait Int: + Clone + + Copy + + fmt::Debug + + fmt::Display + + fmt::LowerHex + + ops::Add<Output = Self> + + ops::Sub<Output = Self> + + ops::Shl<u32, Output = Self> + + ops::Shr<u32, Output = Self> + + ops::BitAnd<Output = Self> + + ops::BitOr<Output = Self> + + ops::Not<Output = Self> + + ops::AddAssign + + ops::BitAndAssign + + ops::BitOrAssign + + From<u8> + + TryFrom<i8> + + TryFrom<u32, Error: fmt::Debug> + + TryFrom<u64, Error: fmt::Debug> + + TryFrom<u128, Error: fmt::Debug> + + TryInto<u64, Error: fmt::Debug> + + TryInto<u32, Error: fmt::Debug> + + ToBigInt + + PartialOrd + + Integer + + Send + + 'static +{ + type Signed: Int; + type Bytes: Default + AsMut<[u8]>; + + const BITS: u32; + const ZERO: Self; + const ONE: Self; + const MAX: Self; + + fn to_signed(self) -> Self::Signed; + fn wrapping_neg(self) -> Self; + fn trailing_zeros(self) -> u32; + + fn hex(self) -> String { + format!("{self:x}") + } +} + +macro_rules! impl_int { + ($($uty:ty, $sty:ty);+) => { + $( + impl Int for $uty { + type Signed = $sty; + type Bytes = [u8; Self::BITS as usize / 8]; + const BITS: u32 = Self::BITS; + const ZERO: Self = 0; + const ONE: Self = 1; + const MAX: Self = Self::MAX; + fn to_signed(self) -> Self::Signed { + self.try_into().unwrap() + } + fn wrapping_neg(self) -> Self { + self.wrapping_neg() + } + fn trailing_zeros(self) -> u32 { + self.trailing_zeros() + } + } + + impl Int for $sty { + type Signed = Self; + type Bytes = [u8; Self::BITS as usize / 8]; + const BITS: u32 = Self::BITS; + const ZERO: Self = 0; + const ONE: Self = 1; + const MAX: Self = Self::MAX; + fn to_signed(self) -> Self::Signed { + self + } + fn wrapping_neg(self) -> Self { + self.wrapping_neg() + } + fn trailing_zeros(self) -> u32 { + self.trailing_zeros() + } + } + )+ + } +} + +impl_int!(u32, i32; u64, i64); + +/// Floating point types. +pub trait Float: + Copy + fmt::Debug + fmt::LowerExp + FromStr<Err: fmt::Display> + Sized + Send + 'static +{ + /// Unsigned integer of same width + type Int: Int<Signed = Self::SInt>; + type SInt: Int; + + /// Total bits + const BITS: u32; + + /// (Stored) bits in the mantissa) + const MAN_BITS: u32; + + /// Bits in the exponent + const EXP_BITS: u32 = Self::BITS - Self::MAN_BITS - 1; + + /// A saturated exponent (all ones) + const EXP_SAT: u32 = (1 << Self::EXP_BITS) - 1; + + /// The exponent bias, also its maximum value + const EXP_BIAS: u32 = Self::EXP_SAT >> 1; + + const MAN_MASK: Self::Int; + const SIGN_MASK: Self::Int; + + fn from_bits(i: Self::Int) -> Self; + fn to_bits(self) -> Self::Int; + + /// Rational constants associated with this float type. + fn constants() -> &'static Constants; + + fn is_sign_negative(self) -> bool { + (self.to_bits() & Self::SIGN_MASK) > Self::Int::ZERO + } + + /// Exponent without adjustment for bias. + fn exponent(self) -> u32 { + ((self.to_bits() >> Self::MAN_BITS) & Self::EXP_SAT.try_into().unwrap()).try_into().unwrap() + } + + fn mantissa(self) -> Self::Int { + self.to_bits() & Self::MAN_MASK + } +} + +macro_rules! impl_float { + ($($fty:ty, $ity:ty, $bits:literal);+) => { + $( + impl Float for $fty { + type Int = $ity; + type SInt = <Self::Int as Int>::Signed; + const BITS: u32 = $bits; + const MAN_BITS: u32 = Self::MANTISSA_DIGITS - 1; + const MAN_MASK: Self::Int = (Self::Int::ONE << Self::MAN_BITS) - Self::Int::ONE; + const SIGN_MASK: Self::Int = Self::Int::ONE << (Self::BITS-1); + fn from_bits(i: Self::Int) -> Self { Self::from_bits(i) } + fn to_bits(self) -> Self::Int { self.to_bits() } + fn constants() -> &'static Constants { + use std::sync::LazyLock; + static CONSTANTS: LazyLock<Constants> = LazyLock::new(Constants::new::<$fty>); + &CONSTANTS + } + } + )+ + } +} + +impl_float!(f32, u32, 32; f64, u64, 64); + +/// A test generator. Should provide an iterator that produces unique patterns to parse. +/// +/// The iterator needs to provide a `WriteCtx` (could be anything), which is then used to +/// write the string at a later step. This is done separately so that we can reuse string +/// allocations (which otherwise turn out to be a pretty expensive part of these tests). +pub trait Generator<F: Float>: Iterator<Item = Self::WriteCtx> + Send + 'static { + /// Full display and filtering name + const NAME: &'static str; + + /// Name for display with the progress bar + const SHORT_NAME: &'static str; + + /// The context needed to create a test string. + type WriteCtx: Send; + + /// Number of tests that will be run. + fn total_tests() -> u64; + + /// Constructor for this test generator. + fn new() -> Self; + + /// Create a test string given write context, which was produced as a step from the iterator. + /// + /// `s` will be provided empty. + fn write_string(s: &mut String, ctx: Self::WriteCtx); +} + +/// For tests that use iterator combinators, it is easier to just to box the iterator than trying +/// to specify its type. This is a shorthand for the usual type. +pub type BoxGenIter<This, F> = Box<dyn Iterator<Item = <This as Generator<F>>::WriteCtx> + Send>; diff --git a/src/etc/test-float-parse/src/ui.rs b/src/etc/test-float-parse/src/ui.rs new file mode 100644 index 00000000000..f333bd4a55d --- /dev/null +++ b/src/etc/test-float-parse/src/ui.rs @@ -0,0 +1,132 @@ +//! Progress bars and such. + +use std::io::{self, Write}; +use std::process::ExitCode; +use std::time::Duration; + +use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; + +use crate::{Completed, Config, EarlyExit, FinishedAll, TestInfo}; + +/// Templates for progress bars. +const PB_TEMPLATE: &str = "[{elapsed:3} {percent:3}%] {bar:20.cyan/blue} NAME ({pos}/{len}, {msg} f, {per_sec}, eta {eta})"; +const PB_TEMPLATE_FINAL: &str = + "[{elapsed:3} {percent:3}%] NAME ({pos}/{len}, {msg:.COLOR}, {per_sec}, {elapsed_precise})"; + +/// Create a new progress bar within a multiprogress bar. +pub fn create_pb( + mp: &MultiProgress, + total_tests: u64, + short_name_padded: &str, + all_bars: &mut Vec<ProgressBar>, +) -> ProgressBar { + let pb = mp.add(ProgressBar::new(total_tests)); + let pb_style = ProgressStyle::with_template(&PB_TEMPLATE.replace("NAME", short_name_padded)) + .unwrap() + .progress_chars("##-"); + + pb.set_style(pb_style.clone()); + pb.set_message("0"); + all_bars.push(pb.clone()); + pb +} + +/// Removes the status bar and replace it with a message. +pub fn finalize_pb(pb: &ProgressBar, short_name_padded: &str, c: &Completed) { + let f = c.failures; + + // Use a tuple so we can use colors + let (color, msg, finish_pb): (&str, String, fn(&ProgressBar, String)) = match &c.result { + Ok(FinishedAll) if f > 0 => { + ("red", format!("{f} f (finished with errors)",), ProgressBar::finish_with_message) + } + Ok(FinishedAll) => { + ("green", format!("{f} f (finished successfully)",), ProgressBar::finish_with_message) + } + Err(EarlyExit::Timeout) => { + ("red", format!("{f} f (timed out)"), ProgressBar::abandon_with_message) + } + Err(EarlyExit::MaxFailures) => { + ("red", format!("{f} f (failure limit)"), ProgressBar::abandon_with_message) + } + }; + + let pb_style = ProgressStyle::with_template( + &PB_TEMPLATE_FINAL.replace("NAME", short_name_padded).replace("COLOR", color), + ) + .unwrap(); + + pb.set_style(pb_style); + finish_pb(pb, msg); +} + +/// Print final messages after all tests are complete. +pub fn finish(tests: &[TestInfo], total_elapsed: Duration, cfg: &Config) -> ExitCode { + println!("\n\nResults:"); + + let mut failed_generators = 0; + let mut stopped_generators = 0; + + for t in tests { + let Completed { executed, failures, elapsed, warning, result } = t.completed.get().unwrap(); + + let stat = if result.is_err() { + stopped_generators += 1; + "STOPPED" + } else if *failures > 0 { + failed_generators += 1; + "FAILURE" + } else { + "SUCCESS" + }; + + println!( + " {stat} for generator '{name}'. {passed}/{executed} passed in {elapsed:?}", + name = t.name, + passed = executed - failures, + ); + + if let Some(warning) = warning { + println!(" warning: {warning}"); + } + + match result { + Ok(FinishedAll) => (), + Err(EarlyExit::Timeout) => { + println!(" exited early; exceded {:?} timeout", cfg.timeout) + } + Err(EarlyExit::MaxFailures) => { + println!(" exited early; exceeded {:?} max failures", cfg.max_failures) + } + } + } + + println!( + "{passed}/{} tests succeeded in {total_elapsed:?} ({passed} passed, {} failed, {} stopped)", + tests.len(), + failed_generators, + stopped_generators, + passed = tests.len() - failed_generators - stopped_generators, + ); + + if failed_generators > 0 || stopped_generators > 0 { + ExitCode::FAILURE + } else { + ExitCode::SUCCESS + } +} + +/// indicatif likes to eat panic messages. This workaround isn't ideal, but it improves things. +/// <https://github.com/console-rs/indicatif/issues/121>. +pub fn set_panic_hook(drop_bars: Vec<ProgressBar>) { + let hook = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |info| { + for bar in &drop_bars { + bar.abandon(); + println!(); + io::stdout().flush().unwrap(); + io::stderr().flush().unwrap(); + } + hook(info); + })); +} diff --git a/src/etc/test-float-parse/src/validate.rs b/src/etc/test-float-parse/src/validate.rs new file mode 100644 index 00000000000..1eb3699cfb9 --- /dev/null +++ b/src/etc/test-float-parse/src/validate.rs @@ -0,0 +1,364 @@ +//! Everything related to verifying that parsed outputs are correct. + +use std::any::type_name; +use std::collections::BTreeMap; +use std::ops::RangeInclusive; +use std::str::FromStr; +use std::sync::LazyLock; + +use num::bigint::ToBigInt; +use num::{BigInt, BigRational, FromPrimitive, Signed, ToPrimitive}; + +use crate::{CheckFailure, Float, Int, Update}; + +/// Powers of two that we store for constants. Account for binary128 which has a 15-bit exponent. +const POWERS_OF_TWO_RANGE: RangeInclusive<i32> = (-(2 << 15))..=(2 << 15); + +/// Powers of ten that we cache. Account for binary128, which can fit +4932/-4931 +const POWERS_OF_TEN_RANGE: RangeInclusive<i32> = -5_000..=5_000; + +/// Cached powers of 10 so we can look them up rather than recreating. +static POWERS_OF_TEN: LazyLock<BTreeMap<i32, BigRational>> = LazyLock::new(|| { + POWERS_OF_TEN_RANGE.map(|exp| (exp, BigRational::from_u32(10).unwrap().pow(exp))).collect() +}); + +/// Rational property-related constants for a specific float type. +#[allow(dead_code)] +#[derive(Debug)] +pub struct Constants { + /// The minimum positive value (a subnormal). + min_subnormal: BigRational, + /// The maximum possible finite value. + max: BigRational, + /// Cutoff between rounding to zero and rounding to the minimum value (min subnormal). + zero_cutoff: BigRational, + /// Cutoff between rounding to the max value and rounding to infinity. + inf_cutoff: BigRational, + /// Opposite of `inf_cutoff` + neg_inf_cutoff: BigRational, + /// The powers of two for all relevant integers. + powers_of_two: BTreeMap<i32, BigRational>, + /// Half of each power of two. ULP = "unit in last position". + /// + /// This is a mapping from integers to half the precision available at that exponent. In other + /// words, `0.5 * 2^n` = `2^(n-1)`, which is half the distance between `m * 2^n` and + /// `(m + 1) * 2^n`, m ∈ ℤ. + /// + /// So, this is the maximum error from a real number to its floating point representation, + /// assuming the float type can represent the exponent. + half_ulp: BTreeMap<i32, BigRational>, + /// Handy to have around so we don't need to reallocate for it + two: BigInt, +} + +impl Constants { + pub fn new<F: Float>() -> Self { + let two_int = &BigInt::from_u32(2).unwrap(); + let two = &BigRational::from_integer(2.into()); + + // The minimum subnormal (aka minimum positive) value. Most negative power of two is the + // minimum exponent (bias - 1) plus the extra from shifting within the mantissa bits. + let min_subnormal = two.pow(-(F::EXP_BIAS + F::MAN_BITS - 1).to_signed()); + + // The maximum value is the maximum exponent with a fully saturated mantissa. This + // is easiest to calculate by evaluating what the next value up would be if representable + // (zeroed mantissa, exponent increments by one, i.e. `2^(bias + 1)`), and subtracting + // a single LSB (`2 ^ (-mantissa_bits)`). + let max = (two - two.pow(-F::MAN_BITS.to_signed())) * (two.pow(F::EXP_BIAS.to_signed())); + let zero_cutoff = &min_subnormal / two_int; + + let inf_cutoff = &max + two_int.pow(F::EXP_BIAS - F::MAN_BITS - 1); + let neg_inf_cutoff = -&inf_cutoff; + + let powers_of_two: BTreeMap<i32, _> = + (POWERS_OF_TWO_RANGE).map(|n| (n, two.pow(n))).collect(); + let mut half_ulp = powers_of_two.clone(); + half_ulp.iter_mut().for_each(|(_k, v)| *v = &*v / two_int); + + Self { + min_subnormal, + max, + zero_cutoff, + inf_cutoff, + neg_inf_cutoff, + powers_of_two, + half_ulp, + two: two_int.clone(), + } + } +} + +/// Validate that a string parses correctly +pub fn validate<F: Float>(input: &str) -> Result<(), Update> { + let parsed: F = input + .parse() + .unwrap_or_else(|e| panic!("parsing failed for {}: {e}. Input: {input}", type_name::<F>())); + + // Parsed float, decoded into significand and exponent + let decoded = decode(parsed); + + // Float parsed separately into a rational + let rational = Rational::parse(input); + + // Verify that the values match + decoded.check(rational, input) +} + +/// The result of parsing a string to a float type. +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum FloatRes<F: Float> { + Inf, + NegInf, + Zero, + Nan, + /// A real number with significand and exponent. Value is `sig * 2 ^ exp`. + Real { + sig: F::SInt, + exp: i32, + }, +} + +impl<F: Float> FloatRes<F> { + /// Given a known exact rational, check that this representation is accurate within the + /// limits of the float representation. If not, construct a failure `Update` to send. + fn check(self, expected: Rational, input: &str) -> Result<(), Update> { + let consts = F::constants(); + // let bool_helper = |cond: bool, err| cond.then_some(()).ok_or(err); + + let res = match (expected, self) { + // Easy correct cases + (Rational::Inf, FloatRes::Inf) + | (Rational::NegInf, FloatRes::NegInf) + | (Rational::Nan, FloatRes::Nan) => Ok(()), + + // Easy incorrect cases + ( + Rational::Inf, + FloatRes::NegInf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. }, + ) => Err(CheckFailure::ExpectedInf), + ( + Rational::NegInf, + FloatRes::Inf | FloatRes::Zero | FloatRes::Nan | FloatRes::Real { .. }, + ) => Err(CheckFailure::ExpectedNegInf), + ( + Rational::Nan, + FloatRes::Inf | FloatRes::NegInf | FloatRes::Zero | FloatRes::Real { .. }, + ) => Err(CheckFailure::ExpectedNan), + (Rational::Finite(_), FloatRes::Nan) => Err(CheckFailure::UnexpectedNan), + + // Cases near limits + (Rational::Finite(r), FloatRes::Zero) => { + if r <= consts.zero_cutoff { + Ok(()) + } else { + Err(CheckFailure::UnexpectedZero) + } + } + (Rational::Finite(r), FloatRes::Inf) => { + if r >= consts.inf_cutoff { + Ok(()) + } else { + Err(CheckFailure::UnexpectedInf) + } + } + (Rational::Finite(r), FloatRes::NegInf) => { + if r <= consts.neg_inf_cutoff { + Ok(()) + } else { + Err(CheckFailure::UnexpectedNegInf) + } + } + + // Actual numbers + (Rational::Finite(r), FloatRes::Real { sig, exp }) => Self::validate_real(r, sig, exp), + }; + + res.map_err(|fail| Update::Failure { + fail, + input: input.into(), + float_res: format!("{self:?}").into(), + }) + } + + /// Check that `sig * 2^exp` is the same as `rational`, within the float's error margin. + fn validate_real(rational: BigRational, sig: F::SInt, exp: i32) -> Result<(), CheckFailure> { + let consts = F::constants(); + + // `2^exp`. Use cached powers of two to be faster. + let two_exp = consts + .powers_of_two + .get(&exp) + .unwrap_or_else(|| panic!("missing exponent {exp} for {}", type_name::<F>())); + + // Rational from the parsed value, `sig * 2^exp` + let parsed_rational = two_exp * sig.to_bigint().unwrap(); + let error = (parsed_rational - &rational).abs(); + + // Determine acceptable error at this exponent, which is halfway between this value + // (`sig * 2^exp`) and the next value up (`(sig+1) * 2^exp`). + let half_ulp = consts.half_ulp.get(&exp).unwrap(); + + // If we are within one error value (but not equal) then we rounded correctly. + if &error < half_ulp { + return Ok(()); + } + + // For values where we are exactly between two representable values, meaning that the error + // is exactly one half of the precision at that exponent, we need to round to an even + // binary value (i.e. mantissa ends in 0). + let incorrect_midpoint_rounding = if &error == half_ulp { + if sig & F::SInt::ONE == F::SInt::ZERO { + return Ok(()); + } + + // We rounded to odd rather than even; failing based on midpoint rounding. + true + } else { + // We are out of spec for some other reason. + false + }; + + let one_ulp = consts.half_ulp.get(&(exp + 1)).unwrap(); + assert_eq!(one_ulp, &(half_ulp * &consts.two), "ULP values are incorrect"); + + let relative_error = error / one_ulp; + + Err(CheckFailure::InvalidReal { + error_float: relative_error.to_f64(), + error_str: relative_error.to_string().into(), + incorrect_midpoint_rounding, + }) + } + + /// Remove trailing zeros in the significand and adjust the exponent + #[cfg(test)] + fn normalize(self) -> Self { + use std::cmp::min; + + match self { + Self::Real { sig, exp } => { + // If there are trailing zeroes, remove them and increment the exponent instead + let shift = min(sig.trailing_zeros(), exp.wrapping_neg().try_into().unwrap()); + Self::Real { sig: sig >> shift, exp: exp + i32::try_from(shift).unwrap() } + } + _ => self, + } + } +} + +/// Decompose a float into its integral components. This includes the implicit bit. +/// +/// If `allow_nan` is `false`, panic if `NaN` values are reached. +fn decode<F: Float>(f: F) -> FloatRes<F> { + let ione = F::SInt::ONE; + let izero = F::SInt::ZERO; + + let mut exponent_biased = f.exponent(); + let mut mantissa = f.mantissa().to_signed(); + + if exponent_biased == 0 { + if mantissa == izero { + return FloatRes::Zero; + } + + exponent_biased += 1; + } else if exponent_biased == F::EXP_SAT { + if mantissa != izero { + return FloatRes::Nan; + } + + if f.is_sign_negative() { + return FloatRes::NegInf; + } + + return FloatRes::Inf; + } else { + // Set implicit bit + mantissa |= ione << F::MAN_BITS; + } + + let mut exponent = i32::try_from(exponent_biased).unwrap(); + + // Adjust for bias and the rnage of the mantissa + exponent -= i32::try_from(F::EXP_BIAS + F::MAN_BITS).unwrap(); + + if f.is_sign_negative() { + mantissa = mantissa.wrapping_neg(); + } + + FloatRes::Real { sig: mantissa, exp: exponent } +} + +/// A rational or its unrepresentable values. +#[derive(Clone, Debug, PartialEq)] +enum Rational { + Inf, + NegInf, + Nan, + Finite(BigRational), +} + +impl Rational { + /// Turn a string into a rational. `None` if `NaN`. + fn parse(s: &str) -> Rational { + let mut s = s; // lifetime rules + + if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("nan") + || s.eq_ignore_ascii_case("-nan") + { + return Rational::Nan; + } + + if s.strip_prefix('+').unwrap_or(s).eq_ignore_ascii_case("inf") { + return Rational::Inf; + } + + if s.eq_ignore_ascii_case("-inf") { + return Rational::NegInf; + } + + // Fast path; no decimals or exponents ot parse + if s.bytes().all(|b| b.is_ascii_digit() || b == b'-') { + return Rational::Finite(BigRational::from_str(s).unwrap()); + } + + let mut ten_exp: i32 = 0; + + // Remove and handle e.g. `e-4`, `e+10`, `e5` suffixes + if let Some(pos) = s.bytes().position(|b| b == b'e' || b == b'E') { + let (dec, exp) = s.split_at(pos); + s = dec; + ten_exp = exp[1..].parse().unwrap(); + } + + // Remove the decimal and instead change our exponent + // E.g. "12.3456" becomes "123456 * 10^-4" + let mut s_owned; + if let Some(pos) = s.bytes().position(|b| b == b'.') { + ten_exp = ten_exp.checked_sub((s.len() - pos - 1).try_into().unwrap()).unwrap(); + s_owned = s.to_owned(); + s_owned.remove(pos); + s = &s_owned; + } + + // let pow = BigRational::from_u32(10).unwrap().pow(ten_exp); + let pow = + POWERS_OF_TEN.get(&ten_exp).unwrap_or_else(|| panic!("missing power of ten {ten_exp}")); + let r = pow + * BigInt::from_str(s) + .unwrap_or_else(|e| panic!("`BigInt::from_str(\"{s}\")` failed with {e}")); + Rational::Finite(r) + } + + #[cfg(test)] + fn expect_finite(self) -> BigRational { + let Self::Finite(r) = self else { + panic!("got non rational: {self:?}"); + }; + + r + } +} + +#[cfg(test)] +mod tests; diff --git a/src/etc/test-float-parse/src/validate/tests.rs b/src/etc/test-float-parse/src/validate/tests.rs new file mode 100644 index 00000000000..ab0e7d8a7ba --- /dev/null +++ b/src/etc/test-float-parse/src/validate/tests.rs @@ -0,0 +1,149 @@ +use num::ToPrimitive; + +use super::*; + +#[test] +fn test_parse_rational() { + assert_eq!(Rational::parse("1234").expect_finite(), BigRational::new(1234.into(), 1.into())); + assert_eq!( + Rational::parse("-1234").expect_finite(), + BigRational::new((-1234).into(), 1.into()) + ); + assert_eq!(Rational::parse("1e+6").expect_finite(), BigRational::new(1000000.into(), 1.into())); + assert_eq!(Rational::parse("1e-6").expect_finite(), BigRational::new(1.into(), 1000000.into())); + assert_eq!( + Rational::parse("10.4e6").expect_finite(), + BigRational::new(10400000.into(), 1.into()) + ); + assert_eq!( + Rational::parse("10.4e+6").expect_finite(), + BigRational::new(10400000.into(), 1.into()) + ); + assert_eq!( + Rational::parse("10.4e-6").expect_finite(), + BigRational::new(13.into(), 1250000.into()) + ); + assert_eq!( + Rational::parse("10.4243566462342456234124").expect_finite(), + BigRational::new(104243566462342456234124_i128.into(), 10000000000000000000000_i128.into()) + ); + assert_eq!(Rational::parse("inf"), Rational::Inf); + assert_eq!(Rational::parse("+inf"), Rational::Inf); + assert_eq!(Rational::parse("-inf"), Rational::NegInf); + assert_eq!(Rational::parse("NaN"), Rational::Nan); +} + +#[test] +fn test_decode() { + assert_eq!(decode(0f32), FloatRes::Zero); + assert_eq!(decode(f32::INFINITY), FloatRes::Inf); + assert_eq!(decode(f32::NEG_INFINITY), FloatRes::NegInf); + assert_eq!(decode(1.0f32).normalize(), FloatRes::Real { sig: 1, exp: 0 }); + assert_eq!(decode(-1.0f32).normalize(), FloatRes::Real { sig: -1, exp: 0 }); + assert_eq!(decode(100.0f32).normalize(), FloatRes::Real { sig: 100, exp: 0 }); + assert_eq!(decode(100.5f32).normalize(), FloatRes::Real { sig: 201, exp: -1 }); + assert_eq!(decode(-4.004f32).normalize(), FloatRes::Real { sig: -8396997, exp: -21 }); + assert_eq!(decode(0.0004f32).normalize(), FloatRes::Real { sig: 13743895, exp: -35 }); + assert_eq!(decode(f32::from_bits(0x1)).normalize(), FloatRes::Real { sig: 1, exp: -149 }); +} + +#[test] +fn test_validate() { + validate::<f32>("0").unwrap(); + validate::<f32>("-0").unwrap(); + validate::<f32>("1").unwrap(); + validate::<f32>("-1").unwrap(); + validate::<f32>("1.1").unwrap(); + validate::<f32>("-1.1").unwrap(); + validate::<f32>("1e10").unwrap(); + validate::<f32>("1e1000").unwrap(); + validate::<f32>("-1e1000").unwrap(); + validate::<f32>("1e-1000").unwrap(); + validate::<f32>("-1e-1000").unwrap(); +} + +#[test] +fn test_validate_real() { + // Most of the arbitrary values come from checking against <http://weitz.de/ieee/>. + let r = &BigRational::from_float(10.0).unwrap(); + FloatRes::<f32>::validate_real(r.clone(), 10, 0).unwrap(); + FloatRes::<f32>::validate_real(r.clone(), 10, -1).unwrap_err(); + FloatRes::<f32>::validate_real(r.clone(), 10, 1).unwrap_err(); + + let r = &BigRational::from_float(0.25).unwrap(); + FloatRes::<f32>::validate_real(r.clone(), 1, -2).unwrap(); + FloatRes::<f32>::validate_real(r.clone(), 2, -2).unwrap_err(); + + let r = &BigRational::from_float(1234.5678).unwrap(); + FloatRes::<f32>::validate_real(r.clone(), 0b100110100101001000101011, -13).unwrap(); + FloatRes::<f32>::validate_real(r.clone(), 0b100110100101001000101010, -13).unwrap_err(); + FloatRes::<f32>::validate_real(r.clone(), 0b100110100101001000101100, -13).unwrap_err(); + + let r = &BigRational::from_float(-1234.5678).unwrap(); + FloatRes::<f32>::validate_real(r.clone(), -0b100110100101001000101011, -13).unwrap(); + FloatRes::<f32>::validate_real(r.clone(), -0b100110100101001000101010, -13).unwrap_err(); + FloatRes::<f32>::validate_real(r.clone(), -0b100110100101001000101100, -13).unwrap_err(); +} + +#[test] +#[allow(unused)] +fn test_validate_real_rounding() { + // Check that we catch when values don't round to even. + + // For f32, the cutoff between 1.0 and the next value up (1.0000001) is + // 1.000000059604644775390625. Anything below it should round down, anything above it should + // round up, and the value itself should round _down_ because `1.0` has an even significand but + // 1.0000001 is odd. + let v1_low_down = Rational::parse("1.00000005960464477539062499999").expect_finite(); + let v1_mid_down = Rational::parse("1.000000059604644775390625").expect_finite(); + let v1_high_up = Rational::parse("1.00000005960464477539062500001").expect_finite(); + + let exp = -(f32::MAN_BITS as i32); + let v1_down_sig = 1 << f32::MAN_BITS; + let v1_up_sig = (1 << f32::MAN_BITS) | 0b1; + + FloatRes::<f32>::validate_real(v1_low_down.clone(), v1_down_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(v1_mid_down.clone(), v1_down_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(v1_high_up.clone(), v1_up_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(-v1_low_down.clone(), -v1_down_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(-v1_mid_down.clone(), -v1_down_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(-v1_high_up.clone(), -v1_up_sig, exp).unwrap(); + + // 1.000000178813934326171875 is between 1.0000001 and the next value up, 1.0000002. The middle + // value here should round _up_ since 1.0000002 has an even mantissa. + let v2_low_down = Rational::parse("1.00000017881393432617187499999").expect_finite(); + let v2_mid_up = Rational::parse("1.000000178813934326171875").expect_finite(); + let v2_high_up = Rational::parse("1.00000017881393432617187500001").expect_finite(); + + let v2_down_sig = v1_up_sig; + let v2_up_sig = (1 << f32::MAN_BITS) | 0b10; + + FloatRes::<f32>::validate_real(v2_low_down.clone(), v2_down_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(v2_mid_up.clone(), v2_up_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(v2_high_up.clone(), v2_up_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(-v2_low_down.clone(), -v2_down_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(-v2_mid_up.clone(), -v2_up_sig, exp).unwrap(); + FloatRes::<f32>::validate_real(-v2_high_up.clone(), -v2_up_sig, exp).unwrap(); + + // Rounding the wrong direction should error + for res in [ + FloatRes::<f32>::validate_real(v1_mid_down.clone(), v1_up_sig, exp), + FloatRes::<f32>::validate_real(v2_mid_up.clone(), v2_down_sig, exp), + FloatRes::<f32>::validate_real(-v1_mid_down.clone(), -v1_up_sig, exp), + FloatRes::<f32>::validate_real(-v2_mid_up.clone(), -v2_down_sig, exp), + ] { + let e = res.unwrap_err(); + let CheckFailure::InvalidReal { incorrect_midpoint_rounding: true, .. } = e else { + panic!("{e:?}"); + }; + } +} + +/// Just a quick check that the constants are what we expect. +#[test] +fn check_constants() { + assert_eq!(f32::constants().max.to_f32().unwrap(), f32::MAX); + assert_eq!(f32::constants().min_subnormal.to_f32().unwrap(), f32::from_bits(0x1)); + assert_eq!(f64::constants().max.to_f64().unwrap(), f64::MAX); + assert_eq!(f64::constants().min_subnormal.to_f64().unwrap(), f64::from_bits(0x1)); +} diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 00973865915..9256330ac7c 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -2062,16 +2062,23 @@ pub(super) fn item_path(ty: ItemType, name: &str) -> String { fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> String { let mut bounds = String::new(); - if !t_bounds.is_empty() { - if !trait_alias { + if t_bounds.is_empty() { + return bounds; + } + let has_lots_of_bounds = t_bounds.len() > 2; + let inter_str = if has_lots_of_bounds { "\n + " } else { " + " }; + if !trait_alias { + if has_lots_of_bounds { + bounds.push_str(":\n "); + } else { bounds.push_str(": "); } - for (i, p) in t_bounds.iter().enumerate() { - if i > 0 { - bounds.push_str(" + "); - } - bounds.push_str(&p.print(cx).to_string()); + } + for (i, p) in t_bounds.iter().enumerate() { + if i > 0 { + bounds.push_str(inter_str); } + bounds.push_str(&p.print(cx).to_string()); } bounds } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 28ed94432c8..41c506f33dc 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -831,6 +831,10 @@ pre, .rustdoc.src .example-wrap { background: var(--table-alt-row-background-color); } +.docblock .stab, .docblock-short .stab { + display: inline-block; +} + /* "where ..." clauses with block display are also smaller */ div.where { white-space: pre-wrap; @@ -953,6 +957,7 @@ table, display: table; padding: 0; margin: 0; + width: 100%; } .item-table > li { display: table-row; @@ -2178,7 +2183,6 @@ in src-script.js and main.js width: 33%; } .item-table > li > div { - padding-bottom: 5px; word-break: break-all; } } diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index a2e7907b532..e0bea5f053d 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -157,6 +157,7 @@ static TARGETS: &[&str] = &[ "wasm32-wasi", "wasm32-wasip1", "wasm32-wasip1-threads", + "wasm32-wasip2", "x86_64-apple-darwin", "x86_64-apple-ios", "x86_64-fortanix-unknown-sgx", diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs index b4522de6897..8be38dc855f 100644 --- a/src/tools/build_helper/src/git.rs +++ b/src/tools/build_helper/src/git.rs @@ -7,7 +7,7 @@ pub struct GitConfig<'a> { } /// Runs a command and returns the output -fn output_result(cmd: &mut Command) -> Result<String, String> { +pub fn output_result(cmd: &mut Command) -> Result<String, String> { let output = match cmd.stderr(Stdio::inherit()).output() { Ok(status) => status, Err(e) => return Err(format!("failed to run command: {:?}: {}", cmd, e)), diff --git a/src/tools/cargo b/src/tools/cargo -Subproject a2b58c3dad4d554ba01ed6c45c41ff85390560f +Subproject 5f6b9a92201d78af75dc24f14662c3e2dacbbbe diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index cce8617821e..b179d7b5249 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -16,6 +16,7 @@ use clippy_utils::source::snippet_opt; use clippy_utils::ty::is_must_use_ty; use clippy_utils::visitors::for_each_expr_without_closures; use clippy_utils::{return_ty, trait_ref_of_method}; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use core::ops::ControlFlow; @@ -117,11 +118,11 @@ fn check_needless_must_use( // Ignore async functions unless Future::Output type is a must_use type if sig.header.is_async() { let infcx = cx.tcx.infer_ctxt().build(); - if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id)) + if let Some(future_ty) = infcx.err_ctxt().get_impl_future_output_ty(return_ty(cx, item_id)) && !is_must_use_ty(cx, future_ty) { return; - } + }; } span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 1fd8faf3ea8..e6506709774 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind}; use rustc_session::declare_lint_pass; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; -use rustc_trait_selection::error_reporting::traits::suggestions::TypeErrCtxtExt; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt}; declare_clippy_lint! { diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 95ae591884b..0d3786dad4b 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -56,19 +56,18 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { let Ok(impls) = cx.tcx.crate_inherent_impls(()) else { return; }; - let inherent_impls = cx - .tcx - .with_stable_hashing_context(|hcx| impls.inherent_impls.to_sorted(&hcx, true)); - for (_, impl_ids) in inherent_impls.into_iter().filter(|(&id, impls)| { - impls.len() > 1 + for (&id, impl_ids) in &impls.inherent_impls { + if impl_ids.len() < 2 // Check for `#[allow]` on the type definition - && !is_lint_allowed( + || is_lint_allowed( cx, MULTIPLE_INHERENT_IMPL, cx.tcx.local_def_id_to_hir_id(id), - ) - }) { + ) { + continue; + } + for impl_id in impl_ids.iter().map(|id| id.expect_local()) { let impl_ty = cx.tcx.type_of(impl_id).instantiate_identity(); match type_map.entry(impl_ty) { diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index 0ecfa7baa72..9d326c06eff 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -15,6 +15,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::impl_lint_pass; use rustc_span::Span; +use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use std::ops::Deref; declare_clippy_lint! { @@ -159,7 +160,7 @@ impl NoEffect { // Remove `impl Future<Output = T>` to get `T` if cx.tcx.ty_is_opaque_future(ret_ty) && let Some(true_ret_ty) = - cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty) + cx.tcx.infer_ctxt().build().err_ctxt().get_impl_future_output_ty(ret_ty) { ret_ty = true_ret_ty; } diff --git a/src/tools/clippy/tests/ui/track-diagnostics.stderr b/src/tools/clippy/tests/ui/track-diagnostics.stderr index 3c7577dd003..83451fb658d 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics.stderr +++ b/src/tools/clippy/tests/ui/track-diagnostics.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | const S: A = B; | ^ expected `A`, found `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC error: aborting due to 1 previous error diff --git a/src/tools/collect-license-metadata/src/main.rs b/src/tools/collect-license-metadata/src/main.rs index cbe94af3510..ca2a6f4b8c8 100644 --- a/src/tools/collect-license-metadata/src/main.rs +++ b/src/tools/collect-license-metadata/src/main.rs @@ -6,16 +6,6 @@ use crate::licenses::LicensesInterner; use anyhow::Error; use std::path::PathBuf; -// Some directories have too many slight license differences that'd result in a -// huge report, and could be considered a standalone project anyway. Those -// directories are "condensed" into a single licensing block for ease of -// reading, merging the licensing information. -// -// For every `(dir, file)``, every file in `dir` is considered to have the -// license info of `file`. -const CONDENSED_DIRECTORIES: &[(&str, &str)] = - &[("./src/llvm-project/", "./src/llvm-project/README.md")]; - fn main() -> Result<(), Error> { let reuse_exe: PathBuf = std::env::var_os("REUSE_EXE").expect("Missing REUSE_EXE").into(); let dest: PathBuf = std::env::var_os("DEST").expect("Missing DEST").into(); diff --git a/src/tools/collect-license-metadata/src/path_tree.rs b/src/tools/collect-license-metadata/src/path_tree.rs index fc8756d9a2e..b27fb7f9225 100644 --- a/src/tools/collect-license-metadata/src/path_tree.rs +++ b/src/tools/collect-license-metadata/src/path_tree.rs @@ -4,7 +4,7 @@ //! passes over the tree to remove redundant information. use crate::licenses::{License, LicenseId, LicensesInterner}; -use std::collections::{BTreeMap, BTreeSet}; +use std::collections::BTreeMap; use std::path::{Path, PathBuf}; #[derive(serde::Serialize)] @@ -12,7 +12,6 @@ use std::path::{Path, PathBuf}; pub(crate) enum Node<L> { Root { children: Vec<Node<L>> }, Directory { name: PathBuf, children: Vec<Node<L>>, license: Option<L> }, - CondensedDirectory { name: PathBuf, licenses: Vec<L> }, File { name: PathBuf, license: L }, Group { files: Vec<PathBuf>, directories: Vec<PathBuf>, license: L }, Empty, @@ -59,8 +58,6 @@ impl Node<LicenseId> { directories.entry(name).or_insert_with(Vec::new).append(&mut children); } file @ Node::File { .. } => files.push(file), - // Propagate condensed directories as-is. - condensed @ Node::CondensedDirectory { .. } => files.push(condensed), Node::Empty => {} Node::Root { .. } => { panic!("can't have a root inside another element"); @@ -87,7 +84,6 @@ impl Node<LicenseId> { } Node::Empty => {} Node::File { .. } => {} - Node::CondensedDirectory { .. } => {} Node::Group { .. } => { panic!("Group should not be present at this stage"); } @@ -134,7 +130,6 @@ impl Node<LicenseId> { } } Node::File { .. } => {} - Node::CondensedDirectory { .. } => {} Node::Group { .. } => panic!("group should not be present at this stage"), Node::Empty => {} } @@ -177,9 +172,6 @@ impl Node<LicenseId> { Node::Directory { name: child_child_name, .. } => { *child_child_name = child_name.join(&child_child_name); } - Node::CondensedDirectory { name: child_child_name, .. } => { - *child_child_name = child_name.join(&child_child_name); - } Node::File { name: child_child_name, .. } => { *child_child_name = child_name.join(&child_child_name); } @@ -194,7 +186,6 @@ impl Node<LicenseId> { } Node::Empty => {} Node::File { .. } => {} - Node::CondensedDirectory { .. } => {} Node::Group { .. } => panic!("Group should not be present at this stage"), } } @@ -262,7 +253,6 @@ impl Node<LicenseId> { } } Node::File { .. } => {} - Node::CondensedDirectory { .. } => {} Node::Group { .. } => panic!("FileGroup should not be present at this stage"), Node::Empty => {} } @@ -278,7 +268,6 @@ impl Node<LicenseId> { } children.retain(|child| !matches!(child, Node::Empty)); } - Node::CondensedDirectory { .. } => {} Node::Group { .. } => {} Node::File { .. } => {} Node::Empty => {} @@ -302,24 +291,7 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> { // Ensure reproducibility of all future steps. input.sort(); - let mut condensed_directories = BTreeMap::new(); - 'outer: for (path, license) in input { - // Files in condensed directories are handled separately. - for (condensed_directory, allowed_file) in super::CONDENSED_DIRECTORIES { - if path.starts_with(condensed_directory) { - if path.as_path() == Path::new(allowed_file) { - // The licence on our allowed file is used to represent the entire directory - condensed_directories - .entry(*condensed_directory) - .or_insert_with(BTreeSet::new) - .insert(license); - } else { - // don't add the file - } - continue 'outer; - } - } - + for (path, license) in input { let mut node = Node::File { name: path.file_name().unwrap().into(), license }; for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() { node = Node::Directory { @@ -332,22 +304,6 @@ pub(crate) fn build(mut input: Vec<(PathBuf, LicenseId)>) -> Node<LicenseId> { children.push(node); } - for (path, licenses) in condensed_directories { - let path = Path::new(path); - let mut node = Node::CondensedDirectory { - name: path.file_name().unwrap().into(), - licenses: licenses.iter().copied().collect(), - }; - for component in path.parent().unwrap_or_else(|| Path::new(".")).components().rev() { - node = Node::Directory { - name: component.as_os_str().into(), - children: vec![node], - license: None, - }; - } - children.push(node); - } - Node::Root { children } } @@ -376,10 +332,6 @@ pub(crate) fn expand_interned_licenses( Node::Group { files, directories, license } => { Node::Group { files, directories, license: interner.resolve(license) } } - Node::CondensedDirectory { name, licenses } => Node::CondensedDirectory { - name, - licenses: licenses.into_iter().map(|license| interner.resolve(license)).collect(), - }, Node::Empty => Node::Empty, } } diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index da7f03441e7..bc66dcbfb94 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -760,8 +760,14 @@ pub fn output_testname_unique( /// test/revision should reside. Example: /// /path/to/build/host-triple/test/ui/relative/testname.revision.mode/ pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { - output_relative_path(config, &testpaths.relative_dir) - .join(output_testname_unique(config, testpaths, revision)) + // In run-make tests, constructing a relative path + unique testname causes a double layering + // since revisions are not supported, causing unnecessary nesting. + if config.mode == Mode::RunMake { + output_relative_path(config, &testpaths.relative_dir) + } else { + output_relative_path(config, &testpaths.relative_dir) + .join(output_testname_unique(config, testpaths, revision)) + } } /// Absolute path to the base filename used as output for the given diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 01228869617..53988203136 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3433,29 +3433,51 @@ impl<'test> TestCx<'test> { fn run_rmake_v2_test(&self) { // For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe - // (`rmake.rs`) to run the actual tests. The support library is already built as a tool - // dylib and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`. + // (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust + // library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`. // - // 1. We need to build the recipe `rmake.rs` and link in the support library. - // 2. We need to run the recipe to build and run the tests. - let cwd = env::current_dir().unwrap(); - let src_root = self.config.src_base.parent().unwrap().parent().unwrap(); - let src_root = cwd.join(&src_root); - let build_root = self.config.build_base.parent().unwrap().parent().unwrap(); - let build_root = cwd.join(&build_root); + // 1. We need to build the recipe `rmake.rs` as a binary and link in the `run_make_support` + // library. + // 2. We need to run the recipe binary. + + // So we assume the rust-lang/rust project setup looks like the following (our `.` is the + // top-level directory, irrelevant entries to our purposes omitted): + // + // ``` + // . // <- `source_root` + // ├── build/ // <- `build_root` + // ├── compiler/ + // ├── library/ + // ├── src/ + // │ └── tools/ + // │ └── run_make_support/ + // └── tests + // └── run-make/ + // ``` + + // `source_root` is the top-level directory containing the rust-lang/rust checkout. + let source_root = + self.config.find_rust_src_root().expect("could not determine rust source root"); + // `self.config.build_base` is actually the build base folder + "test" + test suite name, it + // looks like `build/<host_triple>/test/run-make`. But we want `build/<host_triple>/`. Note + // that the `build` directory does not need to be called `build`, nor does it need to be + // under `source_root`, so we must compute it based off of `self.config.build_base`. + let build_root = + self.config.build_base.parent().and_then(Path::parent).unwrap().to_path_buf(); // We construct the following directory tree for each rmake.rs test: // ``` - // base_dir/ + // <base_dir>/ // rmake.exe // rmake_out/ // ``` - // having the executable separate from the output artifacts directory allows the recipes to - // `remove_dir_all($TMPDIR)` without running into permission denied issues because - // the executable is not under the `rmake_out/` directory. + // having the recipe executable separate from the output artifacts directory allows the + // recipes to `remove_dir_all($TMPDIR)` without running into issues related trying to remove + // a currently running executable because the recipe executable is not under the + // `rmake_out/` directory. // // This setup intentionally diverges from legacy Makefile run-make tests. - let base_dir = cwd.join(self.output_base_name()); + let base_dir = self.output_base_name(); if base_dir.exists() { self.aggressive_rm_rf(&base_dir).unwrap(); } @@ -3477,120 +3499,186 @@ impl<'test> TestCx<'test> { } } - // HACK: assume stageN-target, we only want stageN. + // `self.config.stage_id` looks like `stage1-<target_triple>`, but we only want + // the `stage1` part as that is what the output directories of bootstrap are prefixed with. + // Note that this *assumes* build layout from bootstrap is produced as: + // + // ``` + // build/<target_triple>/ // <- this is `build_root` + // ├── stage0 + // ├── stage0-bootstrap-tools + // ├── stage0-codegen + // ├── stage0-rustc + // ├── stage0-std + // ├── stage0-sysroot + // ├── stage0-tools + // ├── stage0-tools-bin + // ├── stage1 + // ├── stage1-std + // ├── stage1-tools + // ├── stage1-tools-bin + // └── test + // ``` + // FIXME(jieyouxu): improve the communication between bootstrap and compiletest here so + // we don't have to hack out a `stageN`. let stage = self.config.stage_id.split('-').next().unwrap(); - // First, we construct the path to the built support library. - let mut support_lib_path = PathBuf::new(); - support_lib_path.push(&build_root); - support_lib_path.push(format!("{}-tools-bin", stage)); - support_lib_path.push("librun_make_support.rlib"); + // In order to link in the support library as a rlib when compiling recipes, we need three + // paths: + // 1. Path of the built support library rlib itself. + // 2. Path of the built support library's dependencies directory. + // 3. Path of the built support library's dependencies' dependencies directory. + // + // The paths look like + // + // ``` + // build/<target_triple>/ + // ├── stageN-tools-bin/ + // │ └── librun_make_support.rlib // <- support rlib itself + // ├── stageN-tools/ + // │ ├── release/deps/ // <- deps of deps + // │ └── <host_triple>/release/deps/ // <- deps + // ``` + // + // FIXME(jieyouxu): there almost certainly is a better way to do this (specifically how the + // support lib and its deps are organized, can't we copy them to the tools-bin dir as + // well?), but this seems to work for now. - let mut stage_std_path = PathBuf::new(); - stage_std_path.push(&build_root); - stage_std_path.push(&stage); - stage_std_path.push("lib"); + let stage_tools_bin = build_root.join(format!("{stage}-tools-bin")); + let support_lib_path = stage_tools_bin.join("librun_make_support.rlib"); - // Then, we need to build the recipe `rmake.rs` and link in the support library. - let recipe_bin = base_dir.join(if self.config.target.contains("windows") { - "rmake.exe" - } else { - "rmake" - }); - - let mut support_lib_deps = PathBuf::new(); - support_lib_deps.push(&build_root); - support_lib_deps.push(format!("{}-tools", stage)); - support_lib_deps.push(&self.config.host); - support_lib_deps.push("release"); - support_lib_deps.push("deps"); - - let mut support_lib_deps_deps = PathBuf::new(); - support_lib_deps_deps.push(&build_root); - support_lib_deps_deps.push(format!("{}-tools", stage)); - support_lib_deps_deps.push("release"); - support_lib_deps_deps.push("deps"); - - debug!(?support_lib_deps); - debug!(?support_lib_deps_deps); - - let orig_dylib_env_paths = + let stage_tools = build_root.join(format!("{stage}-tools")); + let support_lib_deps = stage_tools.join(&self.config.host).join("release").join("deps"); + let support_lib_deps_deps = stage_tools.join("release").join("deps"); + + // To compile the recipe with rustc, we need to provide suitable dynamic library search + // paths to rustc. This includes both: + // 1. The "base" dylib search paths that was provided to compiletest, e.g. `LD_LIBRARY_PATH` + // on some linux distros. + // 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc. + + let base_dylib_search_paths = Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap())); - let mut host_dylib_env_paths = Vec::new(); - host_dylib_env_paths.push(cwd.join(&self.config.compile_lib_path)); - host_dylib_env_paths.extend(orig_dylib_env_paths.iter().cloned()); - let host_dylib_env_paths = env::join_paths(host_dylib_env_paths).unwrap(); + let host_dylib_search_paths = { + let mut paths = vec![self.config.compile_lib_path.clone()]; + paths.extend(base_dylib_search_paths.iter().cloned()); + paths + }; + + // Calculate the paths of the recipe binary. As previously discussed, this is placed at + // `<base_dir>/<bin_name>` with `bin_name` being `rmake` or `rmake.exe` depending on + // platform. + let recipe_bin = { + let mut p = base_dir.join("rmake"); + p.set_extension(env::consts::EXE_EXTENSION); + p + }; - let mut cmd = Command::new(&self.config.rustc_path); - cmd.arg("-o") + let mut rustc = Command::new(&self.config.rustc_path); + rustc + .arg("-o") .arg(&recipe_bin) + // Specify library search paths for `run_make_support`. .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy())) .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy())) .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy())) + // Provide `run_make_support` as extern prelude, so test writers don't need to write + // `extern run_make_support;`. .arg("--extern") .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) .arg("--edition=2021") .arg(&self.testpaths.file.join("rmake.rs")) - .env("TARGET", &self.config.target) - .env("PYTHON", &self.config.python) - .env("RUST_BUILD_STAGE", &self.config.stage_id) - .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) - .env(dylib_env_var(), &host_dylib_env_paths) - .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) - .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) - .env("LLVM_COMPONENTS", &self.config.llvm_components); + // Provide necessary library search paths for rustc. + .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); // In test code we want to be very pedantic about values being silently discarded that are // annotated with `#[must_use]`. - cmd.arg("-Dunused_must_use"); - + rustc.arg("-Dunused_must_use"); + + // > `cg_clif` uses `COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0` for running the rustc + // > test suite. With the introduction of rmake.rs this broke. `librun_make_support.rlib` is + // > compiled using the bootstrap rustc wrapper which sets `--sysroot + // > build/aarch64-unknown-linux-gnu/stage0-sysroot`, but then compiletest will compile + // > `rmake.rs` using the sysroot of the bootstrap compiler causing it to not find the + // > `libstd.rlib` against which `librun_make_support.rlib` is compiled. + // + // The gist here is that we have to pass the proper stage0 sysroot if we want + // + // ``` + // $ COMPILETEST_FORCE_STAGE0=1 ./x test run-make --stage 0 + // ``` + // + // to work correctly. + // + // See <https://github.com/rust-lang/rust/pull/122248> for more background. if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { - let mut stage0_sysroot = build_root.clone(); - stage0_sysroot.push("stage0-sysroot"); - debug!(?stage0_sysroot); - debug!(exists = stage0_sysroot.exists()); - - cmd.arg("--sysroot").arg(&stage0_sysroot); + let stage0_sysroot = build_root.join("stage0-sysroot"); + rustc.arg("--sysroot").arg(&stage0_sysroot); } - let res = self.run_command_to_procres(&mut cmd); + // Now run rustc to build the recipe. + let res = self.run_command_to_procres(&mut rustc); if !res.status.success() { self.fatal_proc_rec("run-make test failed: could not build `rmake.rs` recipe", &res); } - // Finally, we need to run the recipe binary to build and run the actual tests. - debug!(?recipe_bin); + // To actually run the recipe, we have to provide the recipe with a bunch of information + // provided through env vars. + + // Compute stage-specific standard library paths. + let stage_std_path = build_root.join(&stage).join("lib"); - let mut dylib_env_paths = orig_dylib_env_paths.clone(); - dylib_env_paths.push(support_lib_path.parent().unwrap().to_path_buf()); - dylib_env_paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib")); - let dylib_env_paths = env::join_paths(dylib_env_paths).unwrap(); + // Compute dynamic library search paths for recipes. + let recipe_dylib_search_paths = { + let mut paths = base_dylib_search_paths.clone(); + paths.push(support_lib_path.parent().unwrap().to_path_buf()); + paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib")); + paths + }; - let mut target_rpath_env_path = Vec::new(); - target_rpath_env_path.push(&rmake_out_dir); - target_rpath_env_path.extend(&orig_dylib_env_paths); - let target_rpath_env_path = env::join_paths(target_rpath_env_path).unwrap(); + // Compute runtime library search paths for recipes. This is target-specific. + let target_runtime_dylib_search_paths = { + let mut paths = vec![rmake_out_dir.clone()]; + paths.extend(base_dylib_search_paths.iter().cloned()); + paths + }; + // FIXME(jieyouxu): please rename `TARGET_RPATH_ENV`, `HOST_RPATH_DIR` and + // `TARGET_RPATH_DIR`, it is **extremely** confusing! let mut cmd = Command::new(&recipe_bin); cmd.current_dir(&rmake_out_dir) .stdout(Stdio::piped()) .stderr(Stdio::piped()) + // Provide the target-specific env var that is used to record dylib search paths. For + // example, this could be `LD_LIBRARY_PATH` on some linux distros but `PATH` on Windows. .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) - .env("TARGET_RPATH_ENV", &target_rpath_env_path) - .env(dylib_env_var(), &dylib_env_paths) + // Provide the dylib search paths. + .env(dylib_env_var(), &env::join_paths(recipe_dylib_search_paths).unwrap()) + // Provide runtime dylib search paths. + .env("TARGET_RPATH_ENV", &env::join_paths(target_runtime_dylib_search_paths).unwrap()) + // Provide the target. .env("TARGET", &self.config.target) + // Some tests unfortunately still need Python, so provide path to a Python interpreter. .env("PYTHON", &self.config.python) - .env("SOURCE_ROOT", &src_root) - .env("RUST_BUILD_STAGE", &self.config.stage_id) - .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) - .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) + // Provide path to checkout root. This is the top-level directory containing + // rust-lang/rust checkout. + .env("SOURCE_ROOT", &source_root) + // Provide path to stage-corresponding rustc. + .env("RUSTC", &self.config.rustc_path) + // Provide the directory to libraries that are needed to run the *compiler*. This is not + // to be confused with `TARGET_RPATH_ENV` or `TARGET_RPATH_DIR`. This is needed if the + // recipe wants to invoke rustc. + .env("HOST_RPATH_DIR", &self.config.compile_lib_path) + // Provide the directory to libraries that might be needed to run compiled binaries + // (further compiled by the recipe!). + .env("TARGET_RPATH_DIR", &self.config.run_lib_path) + // Provide which LLVM components are available (e.g. which LLVM components are provided + // through a specific CI runner). .env("LLVM_COMPONENTS", &self.config.llvm_components); if let Some(ref rustdoc) = self.config.rustdoc_path { - cmd.env("RUSTDOC", cwd.join(rustdoc)); + cmd.env("RUSTDOC", source_root.join(rustdoc)); } if let Some(ref node) = self.config.nodejs { diff --git a/src/tools/generate-copyright/src/main.rs b/src/tools/generate-copyright/src/main.rs index 558e87290b0..d91b258162e 100644 --- a/src/tools/generate-copyright/src/main.rs +++ b/src/tools/generate-copyright/src/main.rs @@ -1,5 +1,4 @@ use anyhow::Error; -use std::collections::BTreeSet; use std::io::Write; use std::path::PathBuf; @@ -27,7 +26,7 @@ fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<( } } Node::Directory { name, children, license } => { - render_license(&prefix, std::iter::once(name), license.iter(), buffer)?; + render_license(&prefix, std::iter::once(name), license.as_ref(), buffer)?; if !children.is_empty() { writeln!(buffer, "{prefix}")?; writeln!(buffer, "{prefix}*Exceptions:*")?; @@ -37,19 +36,11 @@ fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<( } } } - Node::CondensedDirectory { name, licenses } => { - render_license(&prefix, std::iter::once(name), licenses.iter(), buffer)?; - } Node::Group { files, directories, license } => { - render_license( - &prefix, - directories.iter().chain(files.iter()), - std::iter::once(license), - buffer, - )?; + render_license(&prefix, directories.iter().chain(files.iter()), Some(license), buffer)?; } Node::File { name, license } => { - render_license(&prefix, std::iter::once(name), std::iter::once(license), buffer)?; + render_license(&prefix, std::iter::once(name), Some(license), buffer)?; } } @@ -59,27 +50,17 @@ fn render_recursive(node: &Node, buffer: &mut Vec<u8>, depth: usize) -> Result<( fn render_license<'a>( prefix: &str, names: impl Iterator<Item = &'a String>, - licenses: impl Iterator<Item = &'a License>, + license: Option<&License>, buffer: &mut Vec<u8>, ) -> Result<(), Error> { - let mut spdxs = BTreeSet::new(); - let mut copyrights = BTreeSet::new(); - for license in licenses { - spdxs.insert(&license.spdx); - for copyright in &license.copyright { - copyrights.insert(copyright); - } - } - for name in names { writeln!(buffer, "{prefix}**`{name}`** ")?; } - for spdx in spdxs.iter() { - writeln!(buffer, "{prefix}License: `{spdx}` ")?; - } - for (i, copyright) in copyrights.iter().enumerate() { - let suffix = if i == copyrights.len() - 1 { "" } else { " " }; - writeln!(buffer, "{prefix}Copyright: {copyright}{suffix}")?; + if let Some(license) = license { + writeln!(buffer, "{prefix}License: `{}`", license.spdx)?; + for copyright in license.copyright.iter() { + writeln!(buffer, "{prefix}Copyright: {copyright}")?; + } } Ok(()) @@ -95,7 +76,6 @@ struct Metadata { pub(crate) enum Node { Root { children: Vec<Node> }, Directory { name: String, children: Vec<Node>, license: Option<License> }, - CondensedDirectory { name: String, licenses: Vec<License> }, File { name: String, license: License }, Group { files: Vec<String>, directories: Vec<String>, license: License }, } diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 9eaa234bfaf..0d827ab2e72 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -24,6 +24,7 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ "keyword-idents", "Lints that detect identifiers which will be come keywords in later editions", ), + ("deprecated-safe", "Lints for functions which were erroneously marked as safe in the past"), ]; type LintGroups = BTreeMap<String, BTreeSet<String>>; diff --git a/src/tools/run-make-support/src/external_deps/llvm.rs b/src/tools/run-make-support/src/external_deps/llvm.rs index 5e8ad7ed312..b116bd08e3a 100644 --- a/src/tools/run-make-support/src/external_deps/llvm.rs +++ b/src/tools/run-make-support/src/external_deps/llvm.rs @@ -229,6 +229,8 @@ impl LlvmAr { Self { cmd } } + /// Automatically pass the commonly used arguments `rcus`, used for combining one or more + /// input object files into one output static library file. pub fn obj_to_ar(&mut self) -> &mut Self { self.cmd.arg("rcus"); self diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index e6a45f57de6..b85191970de 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -3,6 +3,10 @@ //! notably is built via cargo: this means that if your test wants some non-trivial utility, such //! as `object` or `wasmparser`, they can be re-exported and be made available through this library. +// We want to control use declaration ordering and spacing (and preserve use group comments), so +// skip rustfmt on this file. +#![cfg_attr(rustfmt, rustfmt::skip)] + mod command; mod macros; mod util; @@ -18,6 +22,8 @@ pub mod scoped_run; pub mod string; pub mod targets; +// Internally we call our fs-related support module as `fs`, but re-export its content as `rfs` +// to tests to avoid colliding with commonly used `use std::fs;`. mod fs; /// [`std::fs`] wrappers and assorted filesystem-related helpers. Public to tests as `rfs` to not be diff --git a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs index cf3d85b4da3..4ec74c0742a 100644 --- a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs +++ b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs @@ -21,6 +21,7 @@ impl PanicContext { #[allow(clippy::print_stderr)] fn init() { let default_hook = panic::take_hook(); + #[allow(deprecated)] let hook = move |panic_info: &panic::PanicInfo<'_>| { with_ctx(|ctx| { if !ctx.is_empty() { diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock new file mode 100644 index 00000000000..75b89a162e9 --- /dev/null +++ b/src/tools/rustbook/Cargo.lock @@ -0,0 +1,1762 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "ammonia" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459" +dependencies = [ + "html5ever", + "maplit", + "once_cell", + "tendril", + "url", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cc" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.6", +] + +[[package]] +name = "clap" +version = "4.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64acc1846d54c1fe936a78dc189c34e28d3f5afc348403f28ecf53660b9b8462" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8393d67ba2e7bfaf28a23458e4e2b543cc73a99595511eb207fdb8aede942" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_complete" +version = "4.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b4be9c4c4b1f30b78d8a750e0822b6a6102d97e62061c583a6c1dea2dfb33ae" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_derive" +version = "4.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dbus" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +dependencies = [ + "libc", + "libdbus-sys", + "winapi", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "elasticlunr-rs" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41e83863a500656dfa214fee6682de9c5b9f03de6860fec531235ed2ae9f6571" +dependencies = [ + "regex", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "html5ever" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libdbus-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "linereader" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d921fea6860357575519aca014c6e22470585accdd543b370c404a8a72d0dd1d" +dependencies = [ + "memchr", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "maplit" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" + +[[package]] +name = "markup5ever" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45" +dependencies = [ + "log", + "phf", + "phf_codegen", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "mdbook" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" +dependencies = [ + "ammonia", + "anyhow", + "chrono", + "clap", + "clap_complete", + "elasticlunr-rs", + "env_logger", + "handlebars", + "log", + "memchr", + "once_cell", + "opener", + "pulldown-cmark", + "regex", + "serde", + "serde_json", + "shlex", + "tempfile", + "toml 0.5.11", + "topological-sort", +] + +[[package]] +name = "mdbook-i18n-helpers" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c8f972ab672d366c3dad77ea5aa7bae68db2d25fbeb889849f97469d7b658e4" +dependencies = [ + "anyhow", + "chrono", + "mdbook", + "polib", + "pulldown-cmark", + "pulldown-cmark-to-cmark", + "regex", + "semver", + "serde_json", + "syntect", + "textwrap", +] + +[[package]] +name = "mdbook-trpl-listing" +version = "0.1.0" +dependencies = [ + "clap", + "mdbook", + "pulldown-cmark", + "pulldown-cmark-to-cmark", + "serde_json", + "thiserror", + "toml 0.8.14", + "xmlparser", +] + +[[package]] +name = "mdbook-trpl-note" +version = "1.0.0" +dependencies = [ + "clap", + "mdbook", + "pulldown-cmark", + "pulldown-cmark-to-cmark", + "serde_json", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "normpath" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "onig" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c4b31c8722ad9171c6d77d3557db078cab2bd50afcc9d09c8b315c59df8ca4f" +dependencies = [ + "bitflags 1.3.2", + "libc", + "once_cell", + "onig_sys", +] + +[[package]] +name = "onig_sys" +version = "69.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b829e3d7e9cc74c7e315ee8edb185bf4190da5acde74afd7fc59c35b1f086e7" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "opener" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8df34be653210fbe9ffaff41d3b92721c56ce82dfee58ee684f9afb5e3a90c0" +dependencies = [ + "bstr", + "dbus", + "normpath", + "windows-sys 0.52.0", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_codegen" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "plist" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" +dependencies = [ + "base64", + "indexmap", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "polib" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b393b155cf9be86249cba1b56cc81be0e6212c66d94ac0d76d37a1761f3bb1b" +dependencies = [ + "linereader", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulldown-cmark" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" +dependencies = [ + "bitflags 2.6.0", + "getopts", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" + +[[package]] +name = "pulldown-cmark-to-cmark" +version = "13.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f609795c8d835f79dcfcf768415b9fb57ef1b74891e99f86e73f43a7a257163b" +dependencies = [ + "pulldown-cmark", +] + +[[package]] +name = "quick-xml" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustbook" +version = "0.1.0" +dependencies = [ + "clap", + "env_logger", + "mdbook", + "mdbook-i18n-helpers", + "mdbook-trpl-listing", + "mdbook-trpl-note", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syntect" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" +dependencies = [ + "bincode", + "bitflags 1.3.2", + "flate2", + "fnv", + "once_cell", + "onig", + "plist", + "regex-syntax", + "serde", + "serde_derive", + "serde_json", + "thiserror", + "walkdir", + "yaml-rust", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" + +[[package]] +name = "thiserror" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59a3a72298453f564e2b111fa896f8d07fabb36f51f06d7e875fc5e0b5a3ef1" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "topological-sort" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[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_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +dependencies = [ + "memchr", +] + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index 95f1a5d6e1d..51ba58483c5 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -1,3 +1,5 @@ +[workspace] + [package] name = "rustbook" version = "0.1.0" diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 4b50bcb38fd..158d5cc8ade 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,13 +1,9 @@ run-make/branch-protection-check-IBT/Makefile run-make/c-dynamic-dylib/Makefile run-make/c-dynamic-rlib/Makefile -run-make/c-static-dylib/Makefile -run-make/c-static-rlib/Makefile run-make/c-unwind-abi-catch-lib-panic/Makefile -run-make/c-unwind-abi-catch-panic/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile -run-make/compiler-lookup-paths-2/Makefile run-make/compiler-rt-works-on-mingw/Makefile run-make/cross-lang-lto-clang/Makefile run-make/cross-lang-lto-pgo-smoketest/Makefile @@ -21,9 +17,7 @@ run-make/emit-to-stdout/Makefile run-make/export-executable-symbols/Makefile run-make/extern-diff-internal-name/Makefile run-make/extern-flag-disambiguates/Makefile -run-make/extern-fn-generic/Makefile run-make/extern-fn-reachable/Makefile -run-make/extern-fn-with-union/Makefile run-make/extern-multiple-copies/Makefile run-make/extern-multiple-copies2/Makefile run-make/fmt-write-bloat/Makefile @@ -33,18 +27,13 @@ run-make/foreign-rust-exceptions/Makefile run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile run-make/interdependent-c-libraries/Makefile -run-make/issue-107094/Makefile -run-make/issue-14698/Makefile run-make/issue-15460/Makefile -run-make/issue-28595/Makefile -run-make/issue-33329/Makefile run-make/issue-35164/Makefile run-make/issue-36710/Makefile run-make/issue-47551/Makefile run-make/issue-69368/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile run-make/issue-88756-default-output/Makefile -run-make/issue-97463-abi-param-passing/Makefile run-make/jobserver-error/Makefile run-make/libs-through-symlinks/Makefile run-make/libtest-json/Makefile @@ -52,11 +41,9 @@ run-make/libtest-junit/Makefile run-make/libtest-thread-limit/Makefile run-make/link-cfg/Makefile run-make/link-framework/Makefile -run-make/linkage-attr-on-static/Makefile run-make/long-linker-command-lines-cmd-exe/Makefile run-make/long-linker-command-lines/Makefile run-make/lto-linkage-used-attr/Makefile -run-make/lto-no-link-whole-rlib/Makefile run-make/macos-deployment-target/Makefile run-make/min-global-align/Makefile run-make/native-link-modifier-bundle/Makefile @@ -65,7 +52,6 @@ run-make/no-alloc-shim/Makefile run-make/no-builtins-attribute/Makefile run-make/no-duplicate-libs/Makefile run-make/panic-abort-eh_frame/Makefile -run-make/pass-non-c-like-enum-to-c/Makefile run-make/pdb-buildinfo-cl-cmd/Makefile run-make/pgo-gen-lto/Makefile run-make/pgo-gen-no-imp-symbols/Makefile @@ -82,9 +68,7 @@ run-make/redundant-libs/Makefile run-make/remap-path-prefix-dwarf/Makefile run-make/reproducible-build-2/Makefile run-make/reproducible-build/Makefile -run-make/return-non-c-like-enum-from-c/Makefile run-make/rlib-format-packed-bundled-libs-2/Makefile -run-make/rlib-format-packed-bundled-libs-3/Makefile run-make/rlib-format-packed-bundled-libs/Makefile run-make/sanitizer-cdylib-link/Makefile run-make/sanitizer-dylib-link/Makefile @@ -94,12 +78,10 @@ run-make/simd-ffi/Makefile run-make/split-debuginfo/Makefile run-make/stable-symbol-names/Makefile run-make/static-dylib-by-default/Makefile -run-make/staticlib-blank-lib/Makefile run-make/staticlib-dylib-linkage/Makefile run-make/symbol-mangling-hashed/Makefile run-make/symbol-visibility/Makefile run-make/sysroot-crates-are-unstable/Makefile -run-make/test-benches/Makefile run-make/thumb-none-cortex-m/Makefile run-make/thumb-none-qemu/Makefile run-make/translation/Makefile diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index f9bf04626f7..ea03662c584 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -65,11 +65,12 @@ pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>) //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None), ("src/ci/docker/host-x86_64/test-various/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None), - //("src/etc/test-float-parse", &[], None), // FIXME uncomment once all deps are vendored + ("src/etc/test-float-parse", EXCEPTIONS, None), ("src/tools/cargo", EXCEPTIONS_CARGO, None), //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None), + ("src/tools/rustbook", EXCEPTIONS_RUSTBOOK, None), ("src/tools/rustc-perf", EXCEPTIONS_RUSTC_PERF, None), ("src/tools/x", &[], None), // tidy-alphabetical-end @@ -167,6 +168,13 @@ const EXCEPTIONS_RUSTC_PERF: ExceptionList = &[ // tidy-alphabetical-end ]; +const EXCEPTIONS_RUSTBOOK: ExceptionList = &[ + // tidy-alphabetical-start + ("mdbook", "MPL-2.0"), + ("ryu", "Apache-2.0 OR BSL-1.0"), + // tidy-alphabetical-end +]; + const EXCEPTIONS_CRANELIFT: ExceptionList = &[ // tidy-alphabetical-start ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"), diff --git a/src/version b/src/version index dbd41264aa9..71fae54fb27 100644 --- a/src/version +++ b/src/version @@ -1 +1 @@ -1.81.0 +1.82.0 diff --git a/tests/codegen/generic-debug.rs b/tests/codegen/generic-debug.rs index 3423abe7187..0ad0b074657 100644 --- a/tests/codegen/generic-debug.rs +++ b/tests/codegen/generic-debug.rs @@ -1,4 +1,3 @@ -//@ ignore-windows //@ ignore-wasi wasi codegens the main symbol differently //@ compile-flags: -g -C no-prepopulate-passes diff --git a/tests/codegen/issues/issue-58881.rs b/tests/codegen/issues/issue-58881.rs index 759e3b70baa..ba6285f3972 100644 --- a/tests/codegen/issues/issue-58881.rs +++ b/tests/codegen/issues/issue-58881.rs @@ -1,7 +1,6 @@ //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 // //@ only-x86_64 -//@ ignore-windows #![crate_type = "lib"] diff --git a/tests/codegen/mainsubprogram.rs b/tests/codegen/mainsubprogram.rs index 12b24c90229..ce3fe3c8608 100644 --- a/tests/codegen/mainsubprogram.rs +++ b/tests/codegen/mainsubprogram.rs @@ -1,7 +1,6 @@ // This test depends on a patch that was committed to upstream LLVM // before 4.0, formerly backported to the Rust LLVM fork. -//@ ignore-windows //@ ignore-apple //@ ignore-wasi diff --git a/tests/codegen/mainsubprogramstart.rs b/tests/codegen/mainsubprogramstart.rs index 20741791db5..0bcb311644d 100644 --- a/tests/codegen/mainsubprogramstart.rs +++ b/tests/codegen/mainsubprogramstart.rs @@ -1,4 +1,3 @@ -//@ ignore-windows //@ ignore-apple //@ ignore-wasi wasi codegens the main symbol differently diff --git a/tests/codegen/nounwind.rs b/tests/codegen/nounwind.rs index 464bc2535c2..c910644458a 100644 --- a/tests/codegen/nounwind.rs +++ b/tests/codegen/nounwind.rs @@ -1,6 +1,5 @@ //@ aux-build:nounwind.rs //@ compile-flags: -C no-prepopulate-passes -C panic=abort -C metadata=a -//@ ignore-windows //@ ignore-android #![crate_type = "lib"] diff --git a/tests/crashes/119299.rs b/tests/crashes/119299.rs deleted file mode 100644 index c8c10546d94..00000000000 --- a/tests/crashes/119299.rs +++ /dev/null @@ -1,25 +0,0 @@ -//@ known-bug: #119299 -#![feature(adt_const_params)] -#![allow(incomplete_features)] - -use std::marker::ConstParamTy; - -#[derive(Eq, PartialEq)] -struct ConstStrU(*const u8, usize); - -impl ConstParamTy for &'static ConstStrU {} - -impl ConstStrU { - const fn from_bytes(bytes: &'static [u8]) -> Self { - Self(bytes.as_ptr(), bytes.len()) - } -} - -const fn chars_s<const S: &'static ConstStrU>() -> [char; 3] { - ['a','b','c'] -} - -fn main() { - const A: &'static ConstStrU = &ConstStrU::from_bytes(b"abc"); - chars_s::<A>(); -} diff --git a/tests/crashes/127009.rs b/tests/crashes/127009.rs deleted file mode 100644 index 74ca14393e4..00000000000 --- a/tests/crashes/127009.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #127009 - -#![feature(non_lifetime_binders)] - -fn b() -where - for<const C: usize> [(); C]: Copy, -{ -} - -fn main() {} diff --git a/tests/crashes/127351.rs b/tests/crashes/127351.rs new file mode 100644 index 00000000000..e3f41594885 --- /dev/null +++ b/tests/crashes/127351.rs @@ -0,0 +1,17 @@ +//@ known-bug: #127351 +#![feature(lazy_type_alias)] +#![allow(incomplete_features)] + +struct Outer0<'a, T>(ExplicitTypeOutlives<'a, T>); +type ExplicitTypeOutlives<'a, T: 'a> = (&'a (), T); + +pub struct Warns { + _significant_drop: ExplicitTypeOutlives, + field: String, +} + +pub fn test(w: Warns) { + _ = || drop(w.field); +} + +fn main() {} diff --git a/tests/crashes/127353.rs b/tests/crashes/127353.rs new file mode 100644 index 00000000000..9bcb90b5c57 --- /dev/null +++ b/tests/crashes/127353.rs @@ -0,0 +1,18 @@ +//@ known-bug: #127353 +#![feature(type_alias_impl_trait)] +trait Trait<T> {} +type Alias<'a, U> = impl Trait<U>; + +fn f<'a>() -> Alias<'a, ()> {} + +pub enum UninhabitedVariants { + Tuple(Alias), +} + +struct A; + +fn cannot_empty_match_on_enum_with_empty_variants_struct_to_anything(x: UninhabitedVariants) -> A { + match x {} +} + +fn main() {} diff --git a/tests/crashes/127628.rs b/tests/crashes/127628.rs new file mode 100644 index 00000000000..f11ab3f7e8d --- /dev/null +++ b/tests/crashes/127628.rs @@ -0,0 +1,14 @@ +//@ known-bug: #127628 +//@ compile-flags: -Zpolonius=next + +use std::io::{self, Read}; + +pub struct Container<'a> { + reader: &'a mut dyn Read, +} + +impl<'a> Container { + pub fn wrap<'s>(reader: &'s mut dyn io::Read) -> Container<'s> { + Container { reader: reader } + } +} diff --git a/tests/crashes/127643.rs b/tests/crashes/127643.rs new file mode 100644 index 00000000000..a4db9397bde --- /dev/null +++ b/tests/crashes/127643.rs @@ -0,0 +1,18 @@ +//@ known-bug: #127643 + +#![feature(associated_const_equality)] + +fn user() -> impl Owner<dyn Sized, C = 0> {} + +trait Owner<K> { + const C: K; +} +impl<K: ConstDefault> Owner<K> for () { + const C: K = K::DEFAULT; +} + +trait ConstDefault { + const DEFAULT: Self; +} + +fn main() {} diff --git a/tests/crashes/127676.rs b/tests/crashes/127676.rs new file mode 100644 index 00000000000..81149c2ef84 --- /dev/null +++ b/tests/crashes/127676.rs @@ -0,0 +1,8 @@ +//@ known-bug: #127676 +//@ edition:2018 + +#![feature(dyn_star,const_async_blocks)] + +static S: dyn* Send + Sync = async { 42 }; + +pub fn main() {} diff --git a/tests/crashes/127737.rs b/tests/crashes/127737.rs new file mode 100644 index 00000000000..2ee8c769858 --- /dev/null +++ b/tests/crashes/127737.rs @@ -0,0 +1,21 @@ +//@ known-bug: #127737 +//@ compile-flags: -Zmir-opt-level=5 --crate-type lib + +pub trait TestTrait { + type MyType; + fn func() -> Option<Self> + where + Self: Sized; +} + +impl<T> dyn TestTrait<MyType = T> +where + Self: Sized, +{ + pub fn other_func() -> Option<Self> { + match Self::func() { + Some(me) => Some(me), + None => None, + } + } +} diff --git a/tests/crashes/127742.rs b/tests/crashes/127742.rs new file mode 100644 index 00000000000..24add454135 --- /dev/null +++ b/tests/crashes/127742.rs @@ -0,0 +1,11 @@ +//@ known-bug: #127742 +struct Vtable(dyn Cap); // missing lifetime + +trait Cap<'a> {} + +union Transmute { + t: u64, // ICEs with u64, u128, or usize. Correctly errors with u32. + u: &'static Vtable, +} + +const G: &'static Vtable = unsafe { Transmute { t: 1 }.u }; diff --git a/tests/crashes/127880.rs b/tests/crashes/127880.rs new file mode 100644 index 00000000000..6c625eac691 --- /dev/null +++ b/tests/crashes/127880.rs @@ -0,0 +1,5 @@ +//@ known-bug: #127880 +//@ compile-flags: -Cinstrument-coverage + +#[coverage] +fn main() {} diff --git a/tests/crashes/127916.rs b/tests/crashes/127916.rs new file mode 100644 index 00000000000..295c88df857 --- /dev/null +++ b/tests/crashes/127916.rs @@ -0,0 +1,16 @@ +//@ known-bug: #127916 + +trait Trait { + fn foo(&self) -> u32 { 0 } +} + +struct F; +struct S; + +mod to_reuse { + pub fn foo(&self) -> u32 {} +} + +impl Trait S { + reuse to_reuse::foo { self } +} diff --git a/tests/crashes/127972.rs b/tests/crashes/127972.rs new file mode 100644 index 00000000000..d0764f875db --- /dev/null +++ b/tests/crashes/127972.rs @@ -0,0 +1,6 @@ +//@ known-bug: #127962 +#![feature(generic_const_exprs)] + +fn zero_init<const usize: usize>() -> Substs1<{ (N) }> { + Substs1([0; { (usize) }]) +} diff --git a/tests/crashes/128016.rs b/tests/crashes/128016.rs new file mode 100644 index 00000000000..d23721ae14e --- /dev/null +++ b/tests/crashes/128016.rs @@ -0,0 +1,10 @@ +//@ known-bug: #128016 +macro_rules! len { + () => { + target + }; +} + +fn main() { + let val: [str; len!()] = []; +} diff --git a/tests/mir-opt/const_prop/invalid_constant.rs b/tests/mir-opt/const_prop/invalid_constant.rs index 91ee36ae2c5..b59103792bf 100644 --- a/tests/mir-opt/const_prop/invalid_constant.rs +++ b/tests/mir-opt/const_prop/invalid_constant.rs @@ -3,7 +3,7 @@ //@ compile-flags: -Zmir-enable-passes=+RemoveZsts // Verify that we can pretty print invalid constants. -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] #[derive(Copy, Clone)] diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff index 1aeaaff21dc..3b739a25cb8 100644 --- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff @@ -57,9 +57,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 05 00 00 00 03 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs index aca5f047222..9cd485813bc 100644 --- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs @@ -1,6 +1,7 @@ //! Verify that we manage to propagate the value of aggregate `a` even without directly mentioning //! the contained scalars. //@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes const Foo: (u32, u32) = (5, 3); diff --git a/tests/mir-opt/issue_99325.rs b/tests/mir-opt/issue_99325.rs index 2638b69e2ee..4cee4f20b31 100644 --- a/tests/mir-opt/issue_99325.rs +++ b/tests/mir-opt/issue_99325.rs @@ -1,7 +1,7 @@ // skip-filecheck // EMIT_MIR_FOR_EACH_BIT_WIDTH -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] { diff --git a/tests/run-make/c-static-dylib/Makefile b/tests/run-make/c-static-dylib/Makefile deleted file mode 100644 index 05da1743c83..00000000000 --- a/tests/run-make/c-static-dylib/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# This test checks that static Rust linking with C does not encounter any errors, with dynamic dependencies given preference over static. -# See https://github.com/rust-lang/rust/issues/10434 - -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,cfoo) - $(RUSTC) foo.rs -C prefer-dynamic - $(RUSTC) bar.rs - rm $(call NATIVE_STATICLIB,cfoo) - $(call RUN,bar) - $(call REMOVE_DYLIBS,foo) - $(call FAIL,bar) diff --git a/tests/run-make/c-static-dylib/rmake.rs b/tests/run-make/c-static-dylib/rmake.rs new file mode 100644 index 00000000000..12ec06c8199 --- /dev/null +++ b/tests/run-make/c-static-dylib/rmake.rs @@ -0,0 +1,20 @@ +// This test checks that static Rust linking with C does not encounter any errors, +// with dynamic dependencies given preference over static. +// See https://github.com/rust-lang/rust/issues/10434 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{ + build_native_static_lib, dynamic_lib_name, rfs, run, run_fail, rustc, static_lib_name, +}; + +fn main() { + build_native_static_lib("cfoo"); + rustc().input("foo.rs").arg("-Cprefer-dynamic").run(); + rustc().input("bar.rs").run(); + rfs::remove_file(static_lib_name("cfoo")); + run("bar"); + rfs::remove_file(dynamic_lib_name("foo")); + run_fail("bar"); +} diff --git a/tests/run-make/c-static-rlib/Makefile b/tests/run-make/c-static-rlib/Makefile deleted file mode 100644 index 298e432cdb8..00000000000 --- a/tests/run-make/c-static-rlib/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# This test checks that static Rust linking with C does not encounter any errors, with static dependencies given preference over dynamic. (This is the default behaviour.) -# See https://github.com/rust-lang/rust/issues/10434 - -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,cfoo) - $(RUSTC) foo.rs - $(RUSTC) bar.rs - $(call REMOVE_RLIBS,foo) - rm $(call NATIVE_STATICLIB,cfoo) - $(call RUN,bar) diff --git a/tests/run-make/c-static-rlib/rmake.rs b/tests/run-make/c-static-rlib/rmake.rs new file mode 100644 index 00000000000..447e29a14f6 --- /dev/null +++ b/tests/run-make/c-static-rlib/rmake.rs @@ -0,0 +1,17 @@ +// This test checks that static Rust linking with C does not encounter any errors, +// with static dependencies given preference over dynamic. (This is the default behaviour.) +// See https://github.com/rust-lang/rust/issues/10434 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, rfs, run, rust_lib_name, rustc, static_lib_name}; + +fn main() { + build_native_static_lib("cfoo"); + rustc().input("foo.rs").run(); + rustc().input("bar.rs").run(); + rfs::remove_file(rust_lib_name("foo")); + rfs::remove_file(static_lib_name("cfoo")); + run("bar"); +} diff --git a/tests/run-make/c-unwind-abi-catch-panic/Makefile b/tests/run-make/c-unwind-abi-catch-panic/Makefile deleted file mode 100644 index 0a38d838e32..00000000000 --- a/tests/run-make/c-unwind-abi-catch-panic/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -# Exercise unwinding a panic. This catches a panic across an FFI boundary and downcasts it into an integer. The Rust code that panics is in the same directory. -# See https://github.com/rust-lang/rust/commit/baf227ea0c1e07fc54395a51e4b3881d701180cb - -# ignore-cross-compile -# needs-unwind -include ../tools.mk - -all: $(call NATIVE_STATICLIB,add) - $(RUSTC) main.rs - $(call RUN,main) || exit 1 diff --git a/tests/run-make/c-unwind-abi-catch-panic/rmake.rs b/tests/run-make/c-unwind-abi-catch-panic/rmake.rs new file mode 100644 index 00000000000..a99dbd18ec6 --- /dev/null +++ b/tests/run-make/c-unwind-abi-catch-panic/rmake.rs @@ -0,0 +1,18 @@ +// A test for calling `C-unwind` functions across foreign function boundaries (FFI). +// This test triggers a panic when calling a foreign function that calls *back* into Rust. +// This catches a panic across an FFI boundary and downcasts it into an integer. +// The Rust code that panics is in the same directory, unlike `c-unwind-abi-catch-lib-panic`. +// See https://github.com/rust-lang/rust/pull/76570 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed +//@ needs-unwind +// Reason: this test exercises panic unwinding + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("add"); + rustc().input("main.rs").run(); + run("main"); +} diff --git a/tests/run-make/compiler-lookup-paths-2/Makefile b/tests/run-make/compiler-lookup-paths-2/Makefile deleted file mode 100644 index ecc0577384a..00000000000 --- a/tests/run-make/compiler-lookup-paths-2/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# This test checks that extern crate declarations in Cargo without a corresponding declaration in the manifest of a dependency are NOT allowed. -# See https://github.com/rust-lang/rust/pull/21113 - -include ../tools.mk - -all: - mkdir -p $(TMPDIR)/a $(TMPDIR)/b - $(RUSTC) a.rs && mv $(TMPDIR)/liba.rlib $(TMPDIR)/a - $(RUSTC) b.rs -L $(TMPDIR)/a && mv $(TMPDIR)/libb.rlib $(TMPDIR)/b - $(RUSTC) c.rs -L crate=$(TMPDIR)/b -L dependency=$(TMPDIR)/a \ - && exit 1 || exit 0 diff --git a/tests/run-make/compiler-lookup-paths-2/rmake.rs b/tests/run-make/compiler-lookup-paths-2/rmake.rs new file mode 100644 index 00000000000..99efb157b53 --- /dev/null +++ b/tests/run-make/compiler-lookup-paths-2/rmake.rs @@ -0,0 +1,20 @@ +// This test checks that extern crate declarations in Cargo without a corresponding declaration +// in the manifest of a dependency are NOT allowed. The last rustc call does it anyways, which +// should result in a compilation failure. +// See https://github.com/rust-lang/rust/pull/21113 + +use run_make_support::{path, rfs, rust_lib_name, rustc}; + +fn main() { + rfs::create_dir("a"); + rfs::create_dir("b"); + rustc().input("a.rs").run(); + rfs::rename(rust_lib_name("a"), path("a").join(rust_lib_name("a"))); + rustc().input("b.rs").library_search_path("a").run(); + rfs::rename(rust_lib_name("b"), path("b").join(rust_lib_name("b"))); + rustc() + .input("c.rs") + .library_search_path("crate=b") + .library_search_path("dependency=a") + .run_fail(); +} diff --git a/tests/run-make/extern-fn-generic/Makefile b/tests/run-make/extern-fn-generic/Makefile deleted file mode 100644 index 7dceea6cb88..00000000000 --- a/tests/run-make/extern-fn-generic/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,test) - $(RUSTC) testcrate.rs - $(RUSTC) test.rs - $(call RUN,test) || exit 1 diff --git a/tests/run-make/extern-fn-generic/rmake.rs b/tests/run-make/extern-fn-generic/rmake.rs new file mode 100644 index 00000000000..05de839a1b0 --- /dev/null +++ b/tests/run-make/extern-fn-generic/rmake.rs @@ -0,0 +1,16 @@ +// Generic types in foreign-function interfaces were introduced in #15831 - this +// test simply runs a Rust program containing generics that is also reliant on +// a C library, and checks that compilation and execution are successful. +// See https://github.com/rust-lang/rust/pull/15831 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("test"); + rustc().input("testcrate.rs").run(); + rustc().input("test.rs").run(); + run("test"); +} diff --git a/tests/run-make/extern-fn-with-union/Makefile b/tests/run-make/extern-fn-with-union/Makefile deleted file mode 100644 index e6c8c993679..00000000000 --- a/tests/run-make/extern-fn-with-union/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,ctest) - $(RUSTC) testcrate.rs - $(RUSTC) test.rs - $(call RUN,test) || exit 1 diff --git a/tests/run-make/extern-fn-with-union/rmake.rs b/tests/run-make/extern-fn-with-union/rmake.rs new file mode 100644 index 00000000000..200602eabeb --- /dev/null +++ b/tests/run-make/extern-fn-with-union/rmake.rs @@ -0,0 +1,16 @@ +// If an external function from foreign-function interface was called upon, +// its attributes would only be passed to LLVM if and only if it was called in the same crate. +// This caused passing around unions to be incorrect. +// See https://github.com/rust-lang/rust/pull/14191 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("ctest"); + rustc().input("testcrate.rs").run(); + rustc().input("test.rs").run(); + run("test"); +} diff --git a/tests/run-make/issue-14698/foo.rs b/tests/run-make/invalid-tmpdir-env-var/foo.rs index f328e4d9d04..f328e4d9d04 100644 --- a/tests/run-make/issue-14698/foo.rs +++ b/tests/run-make/invalid-tmpdir-env-var/foo.rs diff --git a/tests/run-make/invalid-tmpdir-env-var/rmake.rs b/tests/run-make/invalid-tmpdir-env-var/rmake.rs new file mode 100644 index 00000000000..db44debb319 --- /dev/null +++ b/tests/run-make/invalid-tmpdir-env-var/rmake.rs @@ -0,0 +1,20 @@ +// When the TMP (on Windows) or TMPDIR (on Unix) variable is set to an invalid +// or non-existing directory, this used to cause an internal compiler error (ICE). After the +// addition of proper error handling in #28430, this test checks that the expected message is +// printed. +// See https://github.com/rust-lang/rust/issues/14698 + +use run_make_support::{is_windows, rustc}; + +// NOTE: This is not a UI test despite its simplicity, as the error message contains a path +// with some variability that is difficult to normalize + +fn main() { + let mut rustc = rustc(); + if is_windows() { + rustc.env("TMP", "fake"); + } else { + rustc.env("TMPDIR", "fake"); + } + rustc.input("foo.rs").run_fail().assert_stderr_contains("couldn't create a temp dir"); +} diff --git a/tests/run-make/issue-107094/Makefile b/tests/run-make/issue-107094/Makefile deleted file mode 100644 index d614e3e1055..00000000000 --- a/tests/run-make/issue-107094/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# needs-git-hash - -include ../tools.mk - -all: - $(BARE_RUSTC) --version --verbose | $(CGREP) -i -e "commit-hash: [0-9a-f]{40}" "commit-date: [0-9]{4}-[0-9]{2}-[0-9]{2}" - $(BARE_RUSTDOC) --version --verbose | $(CGREP) -i -e "commit-hash: [0-9a-f]{40}" "commit-date: [0-9]{4}-[0-9]{2}-[0-9]{2}" diff --git a/tests/run-make/issue-14698/Makefile b/tests/run-make/issue-14698/Makefile deleted file mode 100644 index a1cfb5abab5..00000000000 --- a/tests/run-make/issue-14698/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -include ../tools.mk - -all: - TMP=fake TMPDIR=fake $(RUSTC) foo.rs 2>&1 | $(CGREP) "couldn't create a temp dir:" diff --git a/tests/run-make/issue-28595/Makefile b/tests/run-make/issue-28595/Makefile deleted file mode 100644 index 258f9788aaf..00000000000 --- a/tests/run-make/issue-28595/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,a) $(call NATIVE_STATICLIB,b) - $(RUSTC) a.rs - $(RUSTC) b.rs - $(call RUN,b) diff --git a/tests/run-make/issue-33329/Makefile b/tests/run-make/issue-33329/Makefile deleted file mode 100644 index 9c149440d8e..00000000000 --- a/tests/run-make/issue-33329/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk - -all: - $(RUSTC) --target x86_64_unknown-linux-musl main.rs 2>&1 | $(CGREP) \ - "error: Error loading target specification: Could not find specification for target" diff --git a/tests/run-make/issue-33329/main.rs b/tests/run-make/issue-33329/main.rs deleted file mode 100644 index f328e4d9d04..00000000000 --- a/tests/run-make/issue-33329/main.rs +++ /dev/null @@ -1 +0,0 @@ -fn main() {} diff --git a/tests/run-make/issue-97463-abi-param-passing/Makefile b/tests/run-make/issue-97463-abi-param-passing/Makefile deleted file mode 100644 index 7ce7aaeec57..00000000000 --- a/tests/run-make/issue-97463-abi-param-passing/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-msvc - -# The issue exercised by this test, rust-lang/rust#97463, explicitly needs `-O` -# flags (like `-O3`) to reproduce. Thus, we call $(CC) instead of nicer -# alternatives provided by tools.mk like using `COMPILE_OBJ` or using a -# `NATIVE_STATICLIB` dependency. - -all: - $(CC) -c -O3 -o $(TMPDIR)/bad.o bad.c - $(AR) rcs $(TMPDIR)/libbad.a $(TMPDIR)/bad.o - $(RUSTC) param_passing.rs -L$(TMPDIR) -lbad -C opt-level=3 - $(call RUN,param_passing) diff --git a/tests/run-make/linkage-attr-on-static/Makefile b/tests/run-make/linkage-attr-on-static/Makefile deleted file mode 100644 index ef50a7ef9f1..00000000000 --- a/tests/run-make/linkage-attr-on-static/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,foo) - $(RUSTC) bar.rs - $(call RUN,bar) || exit 1 diff --git a/tests/run-make/linkage-attr-on-static/rmake.rs b/tests/run-make/linkage-attr-on-static/rmake.rs new file mode 100644 index 00000000000..cd85542e958 --- /dev/null +++ b/tests/run-make/linkage-attr-on-static/rmake.rs @@ -0,0 +1,15 @@ +// #[linkage] is a useful attribute which can be applied to statics to allow +// external linkage, something which was not possible before #18890. This test +// checks that using this new feature results in successful compilation and execution. +// See https://github.com/rust-lang/rust/pull/18890 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("foo"); + rustc().input("bar.rs").run(); + run("bar"); +} diff --git a/tests/run-make/lto-no-link-whole-rlib/Makefile b/tests/run-make/lto-no-link-whole-rlib/Makefile deleted file mode 100644 index 3e82322e72d..00000000000 --- a/tests/run-make/lto-no-link-whole-rlib/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,foo) $(call NATIVE_STATICLIB,bar) - $(RUSTC) lib1.rs - $(RUSTC) lib2.rs - $(RUSTC) main.rs -Clto - $(call RUN,main) - diff --git a/tests/run-make/lto-no-link-whole-rlib/rmake.rs b/tests/run-make/lto-no-link-whole-rlib/rmake.rs new file mode 100644 index 00000000000..8cd653d5f08 --- /dev/null +++ b/tests/run-make/lto-no-link-whole-rlib/rmake.rs @@ -0,0 +1,18 @@ +// In order to improve linking performance, entire rlibs will only be linked if a dylib is being +// created. Otherwise, an executable will only link one rlib as usual. Linking will fail in this +// test should this optimization be reverted. +// See https://github.com/rust-lang/rust/pull/31460 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("foo"); + build_native_static_lib("bar"); + rustc().input("lib1.rs").run(); + rustc().input("lib2.rs").run(); + rustc().input("main.rs").arg("-Clto").run(); + run("main"); +} diff --git a/tests/run-make/issue-28595/a.c b/tests/run-make/native-lib-load-order/a.c index 7bfd83cca21..7bfd83cca21 100644 --- a/tests/run-make/issue-28595/a.c +++ b/tests/run-make/native-lib-load-order/a.c diff --git a/tests/run-make/issue-28595/a.rs b/tests/run-make/native-lib-load-order/a.rs index 07863cf64d6..07863cf64d6 100644 --- a/tests/run-make/issue-28595/a.rs +++ b/tests/run-make/native-lib-load-order/a.rs diff --git a/tests/run-make/issue-28595/b.c b/tests/run-make/native-lib-load-order/b.c index 6aecb5f9e04..6aecb5f9e04 100644 --- a/tests/run-make/issue-28595/b.c +++ b/tests/run-make/native-lib-load-order/b.c diff --git a/tests/run-make/issue-28595/b.rs b/tests/run-make/native-lib-load-order/b.rs index 1f389859fad..1f389859fad 100644 --- a/tests/run-make/issue-28595/b.rs +++ b/tests/run-make/native-lib-load-order/b.rs diff --git a/tests/run-make/native-lib-load-order/rmake.rs b/tests/run-make/native-lib-load-order/rmake.rs new file mode 100644 index 00000000000..ffe20a64168 --- /dev/null +++ b/tests/run-make/native-lib-load-order/rmake.rs @@ -0,0 +1,16 @@ +// An old compiler bug from 2015 caused native libraries to be loaded in the +// wrong order, causing `b` to be loaded before `a` in this test. If the compilation +// is successful, the libraries were loaded in the correct order. + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("a"); + build_native_static_lib("b"); + rustc().input("a.rs").run(); + rustc().input("b.rs").run(); + run("b"); +} diff --git a/tests/run-make/pass-non-c-like-enum-to-c/Makefile b/tests/run-make/pass-non-c-like-enum-to-c/Makefile deleted file mode 100644 index bd441d321bf..00000000000 --- a/tests/run-make/pass-non-c-like-enum-to-c/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,test) - $(RUSTC) nonclike.rs -L$(TMPDIR) -ltest - $(call RUN,nonclike) diff --git a/tests/run-make/pass-non-c-like-enum-to-c/rmake.rs b/tests/run-make/pass-non-c-like-enum-to-c/rmake.rs new file mode 100644 index 00000000000..c706e82f4a0 --- /dev/null +++ b/tests/run-make/pass-non-c-like-enum-to-c/rmake.rs @@ -0,0 +1,19 @@ +// Similar to the `return-non-c-like-enum-from-c` test, where +// the C code is the library, and the Rust code compiles +// into the executable. Once again, enum variants should be treated +// like an union of structs, which should prevent segfaults or +// unexpected results. The only difference with the aforementioned +// test is that the structs are passed into C directly through the +// `tt_add` and `t_add` function calls. +// See https://github.com/rust-lang/rust/issues/68190 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("test"); + rustc().input("nonclike.rs").arg("-ltest").run(); + run("nonclike"); +} diff --git a/tests/run-make/return-non-c-like-enum-from-c/Makefile b/tests/run-make/return-non-c-like-enum-from-c/Makefile deleted file mode 100644 index bd441d321bf..00000000000 --- a/tests/run-make/return-non-c-like-enum-from-c/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: $(call NATIVE_STATICLIB,test) - $(RUSTC) nonclike.rs -L$(TMPDIR) -ltest - $(call RUN,nonclike) diff --git a/tests/run-make/return-non-c-like-enum-from-c/rmake.rs b/tests/run-make/return-non-c-like-enum-from-c/rmake.rs new file mode 100644 index 00000000000..f24bd6d5fc7 --- /dev/null +++ b/tests/run-make/return-non-c-like-enum-from-c/rmake.rs @@ -0,0 +1,17 @@ +// A reversed version of the `return-non-c-like-enum` test, though +// this time, the C code is the library, and the Rust code compiles +// into the executable. Once again, enum variants should be treated +// like an union of structs, which should prevent segfaults or +// unexpected results. +// See https://github.com/rust-lang/rust/issues/68190 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, run, rustc}; + +fn main() { + build_native_static_lib("test"); + rustc().input("nonclike.rs").arg("-ltest").run(); + run("nonclike"); +} diff --git a/tests/run-make/rlib-format-packed-bundled-libs-3/Makefile b/tests/run-make/rlib-format-packed-bundled-libs-3/Makefile deleted file mode 100644 index 9ba077b1854..00000000000 --- a/tests/run-make/rlib-format-packed-bundled-libs-3/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -include ../tools.mk - -# ignore-cross-compile -# only-linux - -# Make sure -Zpacked_bundled_libs-like behavior activates with +bundle,+whole-archive. - -# We're using the llvm-nm instead of the system nm to ensure it is compatible -# with the LLVM bitcode generated by rustc. -NM = "$(LLVM_BIN_DIR)"/llvm-nm - -all: $(call NATIVE_STATICLIB,native_dep_1) $(call NATIVE_STATICLIB,native_dep_2) $(call NATIVE_STATICLIB,native_dep_3) $(call NATIVE_STATICLIB,native_dep_4) - # test cfg with packed bundle - $(RUSTC) rust_dep_cfg.rs --crate-type=rlib - $(RUSTC) main.rs --extern rust_dep=$(TMPDIR)/librust_dep_cfg.rlib --crate-type=staticlib --cfg should_add - $(AR) t $(TMPDIR)/librust_dep_cfg.rlib | $(CGREP) -e "libnative_dep_1.a" - $(AR) t $(TMPDIR)/librust_dep_cfg.rlib | $(CGREP) -e "libnative_dep_2.a" - $(AR) t $(TMPDIR)/libmain.a | $(CGREP) -e "libnative_dep_1.o" - $(AR) t $(TMPDIR)/libmain.a | $(CGREP) -ev "libnative_dep_2.o" - - - # test bundle with whole_archive - $(RUSTC) rust_dep.rs --crate-type=rlib - $(AR) t $(TMPDIR)/librust_dep.rlib | $(CGREP) -e "native_dep_1" - $(AR) t $(TMPDIR)/librust_dep.rlib | $(CGREP) -e "native_dep_3" - $(AR) t $(TMPDIR)/librust_dep.rlib | $(CGREP) -ev "native_dep_2" - $(AR) t $(TMPDIR)/librust_dep.rlib | $(CGREP) -ev "native_dep_4" - - # Make sure compiler doesn't use files, that it shouldn't know about. - rm $(TMPDIR)/libnative_dep_1.a - rm $(TMPDIR)/libnative_dep_3.a - - $(RUSTC) main.rs --extern rust_dep=$(TMPDIR)/librust_dep.rlib --print link-args > $(TMPDIR)/link_args - cat $(TMPDIR)/link_args | $(CGREP) -ev "native_dep_3" - cat $(TMPDIR)/link_args | $(CGREP) -e "--whole-archive.*native_dep_1.*--whole-archive.*lnative_dep_2.*no-whole-archive.*lnative_dep_4" diff --git a/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs b/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs new file mode 100644 index 00000000000..d152047600f --- /dev/null +++ b/tests/run-make/rlib-format-packed-bundled-libs-3/rmake.rs @@ -0,0 +1,84 @@ +// `-Z packed_bundled_libs` is an unstable rustc flag that makes the compiler +// only require a native library and no supplementary object files to compile. +// #105601 made it possible to have this behaviour without an unstable flag by +// passing +bundle in modifiers, and this test checks that this feature successfully +// compiles and includes only the static libraries, with no object files. +// See https://github.com/rust-lang/rust/pull/105601 + +use run_make_support::{ + build_native_static_lib, is_msvc, llvm_ar, regex, rfs, rust_lib_name, rustc, static_lib_name, +}; + +//@ ignore-cross-compile +// Reason: Invalid library format (not ELF) causes compilation failure +// in the final `rustc` call. + +//@ only-linux +// Reason: differences in the native lib compilation process causes differences +// in the --print link-args output + +fn main() { + build_native_static_lib("native_dep_1"); + build_native_static_lib("native_dep_2"); + build_native_static_lib("native_dep_3"); + build_native_static_lib("native_dep_4"); + // Test cfg with packed bundle. + rustc().input("rust_dep_cfg.rs").crate_type("rlib").run(); + rustc() + .input("main.rs") + .extern_("rust_dep", rust_lib_name("rust_dep_cfg")) + .crate_type("staticlib") + .cfg("should_add") + .run(); + // Only static libraries should appear, no object files at all. + llvm_ar() + .arg("t") + .arg(rust_lib_name("rust_dep_cfg")) + .run() + .assert_stdout_contains(static_lib_name("native_dep_1")); + llvm_ar() + .arg("t") + .arg(rust_lib_name("rust_dep_cfg")) + .run() + .assert_stdout_contains(static_lib_name("native_dep_2")); + llvm_ar().arg("t").arg(static_lib_name("main")).run().assert_stdout_contains("native_dep_1.o"); + llvm_ar() + .arg("t") + .arg(static_lib_name("main")) + .run() + .assert_stdout_not_contains("native_dep_2.o"); + + // Test bundle with whole archive. + rustc().input("rust_dep.rs").crate_type("rlib").run(); + // Only deps with `+bundle` should appear. + llvm_ar().arg("t").arg(rust_lib_name("rust_dep")).run().assert_stdout_contains("native_dep_1"); + llvm_ar().arg("t").arg(rust_lib_name("rust_dep")).run().assert_stdout_contains("native_dep_3"); + llvm_ar() + .arg("t") + .arg(rust_lib_name("rust_dep")) + .run() + .assert_stdout_not_contains("native_dep_2"); + llvm_ar() + .arg("t") + .arg(rust_lib_name("rust_dep")) + .run() + .assert_stdout_not_contains("native_dep_4"); + + // The compiler shouldn't use files which it doesn't know about. + rfs::remove_file(static_lib_name("native_dep_1")); + rfs::remove_file(static_lib_name("native_dep_3")); + + let out = rustc() + .input("main.rs") + .extern_("rust_dep", rust_lib_name("rust_dep")) + .print("link-args") + .run() + .assert_stdout_not_contains("native_dep_3") + .stdout_utf8(); + + let re = regex::Regex::new( +"--whole-archive.*native_dep_1.*--whole-archive.*lnative_dep_2.*no-whole-archive.*lnative_dep_4" + ).unwrap(); + + assert!(re.is_match(&out)); +} diff --git a/tests/run-make/staticlib-blank-lib/Makefile b/tests/run-make/staticlib-blank-lib/Makefile deleted file mode 100644 index fcbf87758fb..00000000000 --- a/tests/run-make/staticlib-blank-lib/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -include ../tools.mk - -all: - $(AR) crus $(TMPDIR)/libfoo.a foo.rs - $(AR) d $(TMPDIR)/libfoo.a foo.rs - $(RUSTC) foo.rs diff --git a/tests/run-make/staticlib-blank-lib/rmake.rs b/tests/run-make/staticlib-blank-lib/rmake.rs new file mode 100644 index 00000000000..11a85d102aa --- /dev/null +++ b/tests/run-make/staticlib-blank-lib/rmake.rs @@ -0,0 +1,13 @@ +// In this test, the static library foo is made blank, which used to cause +// a compilation error. As the compiler now returns Ok upon encountering a blank +// staticlib as of #12379, this test checks that compilation is successful despite +// the blank staticlib. +// See https://github.com/rust-lang/rust/pull/12379 + +use run_make_support::{llvm_ar, rustc, static_lib_name}; + +fn main() { + llvm_ar().obj_to_ar().output_input(static_lib_name("foo"), "foo.rs").run(); + llvm_ar().arg("d").output_input(static_lib_name("foo"), "foo.rs").run(); + rustc().input("foo.rs").run(); +} diff --git a/tests/run-make/test-benches/Makefile b/tests/run-make/test-benches/Makefile deleted file mode 100644 index 11aed2e4c79..00000000000 --- a/tests/run-make/test-benches/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -include ../tools.mk - -# ignore-cross-compile -# needs-unwind #[bench] and -Zpanic-abort-tests can't be combined - -all: - # Smoke-test that `#[bench]` isn't entirely broken. - $(RUSTC) --test smokebench.rs -O - $(call RUN,smokebench --bench) - $(call RUN,smokebench --bench noiter) - $(call RUN,smokebench --bench yesiter) - $(call RUN,smokebench) diff --git a/tests/run-make/test-benches/rmake.rs b/tests/run-make/test-benches/rmake.rs new file mode 100644 index 00000000000..1458fb8c990 --- /dev/null +++ b/tests/run-make/test-benches/rmake.rs @@ -0,0 +1,22 @@ +// #[bench] is a Rust feature to run benchmarks on performance-critical +// code, which previously experienced a runtime panic bug in #103794. +// In order to ensure future breakages of this feature are detected, this +// smoke test was created, using the benchmarking feature with various +// runtime flags. +// See https://github.com/rust-lang/rust/issues/103794 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed +//@ needs-unwind +// Reason: #[bench] and -Zpanic-abort-tests can't be combined + +use run_make_support::{run, run_with_args, rustc}; + +fn main() { + // Smoke-test that #[bench] isn't entirely broken. + rustc().arg("--test").input("smokebench.rs").opt().run(); + run_with_args("smokebench", &["--bench"]); + run_with_args("smokebench", &["--bench", "noiter"]); + run_with_args("smokebench", &["--bench", "yesiter"]); + run("smokebench"); +} diff --git a/tests/run-make/version-verbose-commit-hash/rmake.rs b/tests/run-make/version-verbose-commit-hash/rmake.rs new file mode 100644 index 00000000000..733c0e2cdb1 --- /dev/null +++ b/tests/run-make/version-verbose-commit-hash/rmake.rs @@ -0,0 +1,20 @@ +// `--version --verbose` should display the git-commit hashes of rustc and rustdoc, but this +// functionality was lost due to #104184. After this feature was returned by #109981, this +// test ensures it will not be broken again. +// See https://github.com/rust-lang/rust/issues/107094 + +//@ needs-git-hash + +use run_make_support::{bare_rustc, bare_rustdoc, regex}; + +fn main() { + let out_rustc = + bare_rustc().arg("--version").arg("--verbose").run().stdout_utf8().to_lowercase(); + let out_rustdoc = + bare_rustdoc().arg("--version").arg("--verbose").run().stdout_utf8().to_lowercase(); + let re = + regex::Regex::new(r#"commit-hash: [0-9a-f]{40}\ncommit-date: [0-9]{4}-[0-9]{2}-[0-9]{2}"#) + .unwrap(); + assert!(re.is_match(&out_rustc)); + assert!(re.is_match(&out_rustdoc)); +} diff --git a/tests/run-make/wasm-panic-small/rmake.rs b/tests/run-make/wasm-panic-small/rmake.rs index 8d0944ed98d..e69fbac9635 100644 --- a/tests/run-make/wasm-panic-small/rmake.rs +++ b/tests/run-make/wasm-panic-small/rmake.rs @@ -13,7 +13,14 @@ fn main() { fn test(cfg: &str) { eprintln!("running cfg {cfg:?}"); - rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().cfg(cfg).run(); + rustc() + .input("foo.rs") + .target("wasm32-wasip1") + .arg("-Clto") + .arg("-Cstrip=debuginfo") + .opt() + .cfg(cfg) + .run(); let bytes = rfs::read("foo.wasm"); println!("{}", bytes.len()); diff --git a/tests/run-make/wasm-stringify-ints-small/rmake.rs b/tests/run-make/wasm-stringify-ints-small/rmake.rs index 93eb38b0987..c0448c59c03 100644 --- a/tests/run-make/wasm-stringify-ints-small/rmake.rs +++ b/tests/run-make/wasm-stringify-ints-small/rmake.rs @@ -4,7 +4,13 @@ use run_make_support::{rfs, rustc}; fn main() { - rustc().input("foo.rs").target("wasm32-wasip1").arg("-Clto").opt().run(); + rustc() + .input("foo.rs") + .target("wasm32-wasip1") + .arg("-Clto") + .arg("-Cstrip=debuginfo") + .opt() + .run(); let bytes = rfs::read("foo.wasm"); println!("{}", bytes.len()); diff --git a/tests/run-make/issue-97463-abi-param-passing/bad.c b/tests/run-make/zero-extend-abi-param-passing/bad.c index 013314ab20d..013314ab20d 100644 --- a/tests/run-make/issue-97463-abi-param-passing/bad.c +++ b/tests/run-make/zero-extend-abi-param-passing/bad.c diff --git a/tests/run-make/issue-97463-abi-param-passing/param_passing.rs b/tests/run-make/zero-extend-abi-param-passing/param_passing.rs index c11f3cc72bd..c11f3cc72bd 100644 --- a/tests/run-make/issue-97463-abi-param-passing/param_passing.rs +++ b/tests/run-make/zero-extend-abi-param-passing/param_passing.rs diff --git a/tests/run-make/zero-extend-abi-param-passing/rmake.rs b/tests/run-make/zero-extend-abi-param-passing/rmake.rs new file mode 100644 index 00000000000..aed27f7f5ab --- /dev/null +++ b/tests/run-make/zero-extend-abi-param-passing/rmake.rs @@ -0,0 +1,25 @@ +// This test was created in response to an obscure miscompilation bug, only +// visible with the -O3 flag passed to the cc compiler when trying to obtain +// a native static library for the sake of foreign function interface. This +// flag could cause certain integer types to fail to be zero-extended, resulting +// in type casting errors. After the fix in #97800, this test attempts integer casting +// while simultaneously interfacing with a C library and using the -O3 flag. +// See https://github.com/rust-lang/rust/issues/97463 + +//@ ignore-msvc +// Reason: the rustc compilation fails due to an unresolved external symbol + +//@ ignore-cross-compile +// Reason: The compiled binary is executed. + +use run_make_support::{cc, is_msvc, llvm_ar, run, rustc, static_lib_name}; + +fn main() { + // The issue exercised by this test specifically needs needs `-O` + // flags (like `-O3`) to reproduce. Thus, we call `cc()` instead of + // the nicer `build_native_static_lib`. + cc().arg("-c").arg("-O3").out_exe("bad.o").input("bad.c").run(); + llvm_ar().obj_to_ar().output_input(static_lib_name("bad"), "bad.o").run(); + rustc().input("param_passing.rs").arg("-lbad").opt_level("3").run(); + run("param_passing"); +} diff --git a/tests/rustdoc-gui/item-name-wrap.goml b/tests/rustdoc-gui/item-name-wrap.goml new file mode 100644 index 00000000000..825c16ac5b8 --- /dev/null +++ b/tests/rustdoc-gui/item-name-wrap.goml @@ -0,0 +1,23 @@ +// This test ensures that the item name's width is not wrapped. +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) +// And only two items in it. +assert-count: ("ul.item-table li", 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']", + ["height"], +) + +// We also check that the `item-table` is taking the full width. +compare-elements-size: ( + "#functions", + "ul.item-table", + ["width"], +) diff --git a/tests/rustdoc-gui/source-code-page-code-scroll.goml b/tests/rustdoc-gui/source-code-page-code-scroll.goml index 35f338ea328..31ab281d6ce 100644 --- a/tests/rustdoc-gui/source-code-page-code-scroll.goml +++ b/tests/rustdoc-gui/source-code-page-code-scroll.goml @@ -2,7 +2,7 @@ go-to: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html" set-window-size: (800, 1000) // "scrollWidth" should be superior than "clientWidth". -assert-property: ("body", {"scrollWidth": 1047, "clientWidth": 800}) +assert-property: ("body", {"scrollWidth": 1114, "clientWidth": 800}) // Both properties should be equal (ie, no scroll on the code block). -assert-property: (".example-wrap .rust", {"scrollWidth": 933, "clientWidth": 933}) +assert-property: (".example-wrap .rust", {"scrollWidth": 1000, "clientWidth": 1000}) diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 7e34178e56f..7397992c0ab 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -20,10 +20,10 @@ Also, stop using `bar` as it's <span class="stab deprecated" title="">deprecated Also, stop using `bar` as it's <span class="stab deprecated" title="">deprecated</span>. Also, stop using `bar` as it's <span class="stab deprecated" title="">deprecated</span>. -Finally, you can use `quz` only on <span class="stab portability"><code>Unix or x86-64</code> -</span>. -Finally, you can use `quz` only on <span class="stab portability"><code>Unix or x86-64</code> -</span>. +Finally, you can use `quz` only on <span class="stab portability" data-span="1"><code>Unix or x86-64 +</code></span>. +Finally, you can use `quz` only on <span class="stab portability" data-span="2"><code>Unix or x86-64 +</code></span>. */ use std::convert::AsRef; @@ -614,3 +614,17 @@ pub mod private { B, } } + +pub mod trait_bounds { + pub trait OneBound: Sized {} + pub trait TwoBounds: Sized + Copy {} + pub trait ThreeBounds: Sized + Copy + Eq {} +} + +pub mod short_docs { + /// mult_vec_num(x: &[f64], y: f64) + pub fn mult_vec_num() {} + + /// subt_vec_num(x: &[f64], y: f64) + pub fn subt_vec_num() {} +} diff --git a/tests/rustdoc-gui/stab-in-doc.goml b/tests/rustdoc-gui/stab-in-doc.goml new file mode 100644 index 00000000000..6a03a51fe9f --- /dev/null +++ b/tests/rustdoc-gui/stab-in-doc.goml @@ -0,0 +1,9 @@ +// This test ensure that `stab` elements if used in doc blocks are not breaking the text layout. +go-to: "file://" + |DOC_PATH| + "/test_docs/index.html" +// We make the window wide enough for the two stabs who are looking into to be on the same line. +set-window-size: (1100, 600) +compare-elements-position: ( + ".top-doc .docblock span[data-span='1']", + ".top-doc .docblock span[data-span='2']", + ["y"], +) diff --git a/tests/rustdoc-gui/trait-with-bounds.goml b/tests/rustdoc-gui/trait-with-bounds.goml new file mode 100644 index 00000000000..f076bdd4707 --- /dev/null +++ b/tests/rustdoc-gui/trait-with-bounds.goml @@ -0,0 +1,35 @@ +// Check that if a trait has more than 2 bounds, they are displayed on different lines. + +// It tries to load a JS for each trait but there are none since they're not implemented. +fail-on-request-error: false +go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/trait.OneBound.html" +// They should have the same Y position. +compare-elements-position: ( + ".item-decl code", + ".item-decl a.trait[title='trait core::marker::Sized']", + ["y"], +) +go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/trait.TwoBounds.html" +// They should have the same Y position. +compare-elements-position: ( + ".item-decl code", + ".item-decl a.trait[title='trait core::marker::Copy']", + ["y"], +) +go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/trait.ThreeBounds.html" +// All on their own line. +compare-elements-position-false: ( + ".item-decl code", + ".item-decl a.trait[title='trait core::marker::Sized']", + ["y"], +) +compare-elements-position-false: ( + ".item-decl a.trait[title='trait core::marker::Sized']", + ".item-decl a.trait[title='trait core::marker::Copy']", + ["y"], +) +compare-elements-position-false: ( + ".item-decl a.trait[title='trait core::marker::Copy']", + ".item-decl a.trait[title='trait core::cmp::Eq']", + ["y"], +) diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml index fdf84c3fd29..8df946c6f39 100644 --- a/tests/rustdoc-gui/type-declation-overflow.goml +++ b/tests/rustdoc-gui/type-declation-overflow.goml @@ -8,34 +8,38 @@ fail-on-request-error: false go-to: "file://" + |DOC_PATH| + "/lib2/long_trait/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.html" // We set a fixed size so there is no chance of "random" resize. -set-window-size: (1100, 800) +set-window-size: (710, 800) // Logically, the <body> scroll width should be the width of the window. -assert-property: ("body", {"scrollWidth": "1100"}) -// However, since there is overflow in the type declaration, its scroll width is bigger. -assert-property: ("pre.item-decl", {"scrollWidth": "1324"}) +assert-property: ("body", {"scrollWidth": "710"}) +// We now check that the section width hasn't grown because of it. +assert-property: ("#main-content", {"scrollWidth": "450"}) +// However, since there is overflow in the type declaration, its scroll width is bigger that "#main-content". +assert-property: ("pre.item-decl", {"scrollWidth": "585"}) // In the table-ish view on the module index, the name should not be wrapped more than necessary. go-to: "file://" + |DOC_PATH| + "/lib2/too_long/index.html" // We'll ensure that items with short documentation have the same width. store-property: ("//*[@class='item-table']//*[@class='struct']/..", {"offsetWidth": offset_width}) -assert: |offset_width| == "277" +assert: |offset_width| == "149" assert-property: ("//*[@class='item-table']//*[@class='constant']/..", {"offsetWidth": |offset_width|}) // We now make the same check on type declaration... go-to: "file://" + |DOC_PATH| + "/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html" -assert-property: ("body", {"scrollWidth": "1100"}) +assert-property: ("body", {"scrollWidth": "710"}) +// Getting the width of the "<main>" element. +assert-property: ("main", {"scrollWidth": "510"}) // We now check that the section width hasn't grown because of it. -assert-property: ("#main-content", {"scrollWidth": "840"}) +assert-property: ("#main-content", {"scrollWidth": "450"}) // And now checking that it has scrollable content. assert-property: ("pre.item-decl", {"scrollWidth": "1103"}) // ... and constant. // On a sidenote, it also checks that the (very) long title isn't changing the docblock width. go-to: "file://" + |DOC_PATH| + "/lib2/too_long/constant.ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong.html" -assert-property: ("body", {"scrollWidth": "1100"}) +assert-property: ("body", {"scrollWidth": "710"}) // We now check that the section width hasn't grown because of it. -assert-property: ("#main-content", {"scrollWidth": "840"}) +assert-property: ("#main-content", {"scrollWidth": "450"}) // And now checking that it has scrollable content. assert-property: ("pre.item-decl", {"scrollWidth": "950"}) diff --git a/tests/rustdoc-ui/track-diagnostics.stderr b/tests/rustdoc-ui/track-diagnostics.stderr index f7f3e368a3c..3d17570a7a2 100644 --- a/tests/rustdoc-ui/track-diagnostics.stderr +++ b/tests/rustdoc-ui/track-diagnostics.stderr @@ -3,7 +3,7 @@ error[E0308]: mismatched types | LL | const S: A = B; | ^ expected `A`, found `B` --Ztrack-diagnostics: created at compiler/rustc_infer/src/error_reporting/infer/mod.rs:LL:CC +-Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs:LL:CC error: aborting due to 1 previous error diff --git a/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs b/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs index 5fa6891b23d..e1f19e7e017 100644 --- a/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs +++ b/tests/rustdoc/anchor-id-duplicate-method-name-25001.rs @@ -24,14 +24,14 @@ impl Foo<u32> { } impl<T> Bar for Foo<T> { - //@ has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' 'type Item = T' + // @has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' 'type Item = T' type Item=T; //@ has - '//*[@id="method.quux"]//h4[@class="code-header"]' 'fn quux(self)' fn quux(self) {} } impl<'a, T> Bar for &'a Foo<T> { - //@ has - '//*[@id="associatedtype.Item"]//h4[@class="code-header"]' "type Item = &'a T" + // @has - '//*[@id="associatedtype.Item-1"]//h4[@class="code-header"]' "type Item = &'a T" type Item=&'a T; //@ has - '//*[@id="method.quux-1"]//h4[@class="code-header"]' 'fn quux(self)' diff --git a/tests/rustdoc/const-generics/const-impl.rs b/tests/rustdoc/const-generics/const-impl.rs index ce536291290..279a7842254 100644 --- a/tests/rustdoc/const-generics/const-impl.rs +++ b/tests/rustdoc/const-generics/const-impl.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![crate_name = "foo"] use std::marker::ConstParamTy; diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index 00a97ca1488..57cbe173c78 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -251,7 +251,7 @@ warning: unexpected `cfg` condition value: `zebra` LL | cfg!(target_feature = "zebra"); | ^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 197 more + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, and `avx512vpopcntdq` and 199 more = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: 27 warnings emitted diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 78b7f0f5d99..764f1c86639 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -165,7 +165,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_feature = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` + = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `amx-bf16`, `amx-complex`, `amx-fp16`, `amx-int8`, `amx-tile`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `avxifma`, `avxneconvert`, `avxvnni`, `avxvnniint16`, `avxvnniint8`, `backchain`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vector`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xop`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt` = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` diff --git a/tests/ui/closures/binder/const-bound.rs b/tests/ui/closures/binder/const-bound.rs index b1c79db1375..10d869fcc85 100644 --- a/tests/ui/closures/binder/const-bound.rs +++ b/tests/ui/closures/binder/const-bound.rs @@ -3,5 +3,6 @@ fn main() { for<const N: i32> || -> () {}; - //~^ ERROR late-bound const parameter not allowed on closures + //~^ ERROR late-bound const parameters cannot be used currently + //~| ERROR late-bound const parameter not allowed on closures } diff --git a/tests/ui/closures/binder/const-bound.stderr b/tests/ui/closures/binder/const-bound.stderr index 9c4fd95ed76..b805879f7fa 100644 --- a/tests/ui/closures/binder/const-bound.stderr +++ b/tests/ui/closures/binder/const-bound.stderr @@ -1,3 +1,9 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/const-bound.rs:5:15 + | +LL | for<const N: i32> || -> () {}; + | ^ + warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/const-bound.rs:1:37 | @@ -13,5 +19,5 @@ error: late-bound const parameter not allowed on closures LL | for<const N: i32> || -> () {}; | ^^^^^^^^^^^^ -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs index 6c2a11e0135..f0424e72434 100644 --- a/tests/ui/coherence/negative-coherence/regions-in-canonical.rs +++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.rs @@ -1,13 +1,12 @@ //@ check-pass -#![feature(adt_const_params)] -//~^ WARN the feature `adt_const_params` is incomplete +#![feature(adt_const_params, unsized_const_params)] +//~^ WARN the feature `unsized_const_params` is incomplete #![feature(with_negative_coherence, negative_impls)] pub trait A<const K: &'static str> {} pub trait C {} - struct W<T>(T); // Negative coherence: diff --git a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr index dc8c926f182..72044915294 100644 --- a/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr +++ b/tests/ui/coherence/negative-coherence/regions-in-canonical.stderr @@ -1,8 +1,8 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/regions-in-canonical.rs:3:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/regions-in-canonical.rs:3:30 | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs index 8035fce0914..e90426ec0c7 100644 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs +++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.rs @@ -1,7 +1,6 @@ //@ check-pass #![feature(adt_const_params, lazy_type_alias)] -//~^ WARN: the feature `adt_const_params` is incomplete -//~| WARN: the feature `lazy_type_alias` is incomplete +//~^ WARN: the feature `lazy_type_alias` is incomplete pub type Matrix = [usize; 1]; const EMPTY_MATRIX: Matrix = [0; 1]; diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr index 5c6981077b2..4f5133474c6 100644 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr +++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-1.stderr @@ -1,12 +1,3 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/alias_const_param_ty-1.rs:2:12 - | -LL | #![feature(adt_const_params, lazy_type_alias)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information - = note: `#[warn(incomplete_features)]` on by default - warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/alias_const_param_ty-1.rs:2:30 | @@ -14,6 +5,7 @@ LL | #![feature(adt_const_params, lazy_type_alias)] | ^^^^^^^^^^^^^^^ | = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information + = note: `#[warn(incomplete_features)]` on by default -warning: 2 warnings emitted +warning: 1 warning emitted diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs index a576b75341c..961e1a9cfbf 100644 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs +++ b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.rs @@ -1,6 +1,5 @@ //@ check-pass #![feature(adt_const_params)] -//~^ WARN: the feature `adt_const_params` is incomplete const EMPTY_MATRIX: <Type as Trait>::Matrix = [0; 1]; diff --git a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr b/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr deleted file mode 100644 index dbc8ab71636..00000000000 --- a/tests/ui/const-generics/adt_const_params/alias_const_param_ty-2.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/alias_const_param_ty-2.rs:2:12 - | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information - = note: `#[warn(incomplete_features)]` on by default - -warning: 1 warning emitted - diff --git a/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs b/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs new file mode 100644 index 00000000000..e2ba459f8dd --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs @@ -0,0 +1,7 @@ +#![feature(adt_const_params, unsized_const_params)] + +#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] +pub struct Foo([u8]); + +#[derive(std::marker::ConstParamTy, Eq, PartialEq)] +pub struct GenericNotUnsizedParam<T>(T); diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs index c4d2d02ba70..35539193a27 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs @@ -1,13 +1,13 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] -fn check(_: impl std::marker::ConstParamTy) {} +fn check(_: impl std::marker::UnsizedConstParamTy) {} fn main() { - check(main); //~ error: `fn() {main}` can't be used as a const parameter type - check(|| {}); //~ error: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as a const parameter type - check(main as fn()); //~ error: `fn()` can't be used as a const parameter type - check(&mut ()); //~ error: `&mut ()` can't be used as a const parameter type + check(main); //~ error: `fn() {main}` can't be used as a const parameter type + check(|| {}); //~ error: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as a const parameter type + check(main as fn()); //~ error: `fn()` can't be used as a const parameter type + check(&mut ()); //~ error: `&mut ()` can't be used as a const parameter type check(&mut () as *mut ()); //~ error: `*mut ()` can't be used as a const parameter type - check(&() as *const ()); //~ error: `*const ()` can't be used as a const parameter type + check(&() as *const ()); //~ error: `*const ()` can't be used as a const parameter type } diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr index d96491f4f20..694f5a5c1a9 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr @@ -2,15 +2,15 @@ error[E0277]: `fn() {main}` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:7:11 | LL | check(main); - | ----- ^^^^ the trait `ConstParamTy` is not implemented for fn item `fn() {main}` + | ----- ^^^^ the trait `UnsizedConstParamTy` is not implemented for fn item `fn() {main}` | | | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this function | LL | check(main()); @@ -20,15 +20,15 @@ error[E0277]: `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` can't be used as --> $DIR/const_param_ty_bad.rs:8:11 | LL | check(|| {}); - | ----- ^^^^^ the trait `ConstParamTy` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` + | ----- ^^^^^ the trait `UnsizedConstParamTy` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` | | | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this closure | LL | check(|| {}()); @@ -38,15 +38,15 @@ error[E0277]: `fn()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:9:11 | LL | check(main as fn()); - | ----- ^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `fn()` + | ----- ^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `fn()` | | | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this function pointer | LL | check(main as fn()()); @@ -56,16 +56,16 @@ error[E0277]: `&mut ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:10:11 | LL | check(&mut ()); - | ----- ^^^^^^^ the trait `ConstParamTy` is not implemented for `&mut ()` + | ----- ^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `&mut ()` | | | required by a bound introduced by this call | - = note: `ConstParamTy` is implemented for `&()`, but not for `&mut ()` + = note: `UnsizedConstParamTy` is implemented for `&()`, but not for `&mut ()` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: consider removing the leading `&`-reference | LL - check(&mut ()); @@ -76,31 +76,31 @@ error[E0277]: `*mut ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:11:11 | LL | check(&mut () as *mut ()); - | ----- ^^^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*mut ()` + | ----- ^^^^^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `*mut ()` | | | required by a bound introduced by this call | - = help: the trait `ConstParamTy` is implemented for `()` + = help: the trait `UnsizedConstParamTy` is implemented for `()` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: `*const ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:12:11 | LL | check(&() as *const ()); - | ----- ^^^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `*const ()` + | ----- ^^^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `*const ()` | | | required by a bound introduced by this call | - = help: the trait `ConstParamTy` is implemented for `()` + = help: the trait `UnsizedConstParamTy` is implemented for `()` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::ConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error: aborting due to 6 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs index b0e3b13cc1e..2008a96310a 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.rs @@ -1,10 +1,10 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #[derive(PartialEq, Eq)] struct NotParam; -fn check<T: std::marker::ConstParamTy>() {} +fn check<T: std::marker::ConstParamTy_>() {} fn main() { check::<[NotParam; 0]>(); diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr index 771d661f615..9852e181b9a 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad_empty_array.stderr @@ -2,14 +2,14 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_bad_empty_array.rs:10:13 | LL | check::<[NotParam; 0]>(); - | ^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 0]: ConstParamTy` + | ^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `NotParam`, which is required by `[NotParam; 0]: ConstParamTy_` | - = note: required for `[NotParam; 0]` to implement `ConstParamTy` + = note: required for `[NotParam; 0]` to implement `ConstParamTy_` note: required by a bound in `check` --> $DIR/const_param_ty_bad_empty_array.rs:7:13 | -LL | fn check<T: std::marker::ConstParamTy>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check<T: std::marker::ConstParamTy_>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs index e4dc76703a2..7ffdafa33e9 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs @@ -1,13 +1,13 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #[derive(PartialEq, Eq)] struct NotParam; -fn check<T: std::marker::ConstParamTy + ?Sized>() {} +fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {} fn main() { - check::<&NotParam>(); //~ error: `NotParam` can't be used as a const parameter type - check::<[NotParam]>(); //~ error: `NotParam` can't be used as a const parameter type + check::<&NotParam>(); //~ error: `NotParam` can't be used as a const parameter type + check::<[NotParam]>(); //~ error: `NotParam` can't be used as a const parameter type check::<[NotParam; 17]>(); //~ error: `NotParam` can't be used as a const parameter type } diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr index 83c34c41f10..e63ae582fd5 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr @@ -2,40 +2,40 @@ error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:10:13 | LL | check::<&NotParam>(); - | ^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `&NotParam: ConstParamTy` + | ^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `&NotParam: UnsizedConstParamTy` | - = note: required for `&NotParam` to implement `ConstParamTy` + = note: required for `&NotParam` to implement `UnsizedConstParamTy` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 | -LL | fn check<T: std::marker::ConstParamTy + ?Sized>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13 | LL | check::<[NotParam]>(); - | ^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam]: ConstParamTy` + | ^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam]: UnsizedConstParamTy` | - = note: required for `[NotParam]` to implement `ConstParamTy` + = note: required for `[NotParam]` to implement `UnsizedConstParamTy` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 | -LL | fn check<T: std::marker::ConstParamTy + ?Sized>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13 | LL | check::<[NotParam; 17]>(); - | ^^^^^^^^^^^^^^ the trait `ConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 17]: ConstParamTy` + | ^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `NotParam`, which is required by `[NotParam; 17]: UnsizedConstParamTy` | - = note: required for `[NotParam; 17]` to implement `ConstParamTy` + = note: required for `[NotParam; 17]` to implement `UnsizedConstParamTy` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 | -LL | fn check<T: std::marker::ConstParamTy + ?Sized>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs index bce24059de8..98a8eb6ee95 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs @@ -1,7 +1,9 @@ //@ check-pass + +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -#![feature(adt_const_params)] -use std::marker::ConstParamTy; + +use std::marker::UnsizedConstParamTy; #[derive(PartialEq, Eq)] struct S<T> { @@ -9,16 +11,15 @@ struct S<T> { gen: T, } -impl<T: ConstParamTy> ConstParamTy for S<T> {} +impl<T: UnsizedConstParamTy> UnsizedConstParamTy for S<T> {} -#[derive(PartialEq, Eq, ConstParamTy)] +#[derive(PartialEq, Eq, UnsizedConstParamTy)] struct D<T> { field: u8, gen: T, } - -fn check<T: ConstParamTy + ?Sized>() {} +fn check<T: UnsizedConstParamTy + ?Sized>() {} fn main() { check::<u8>(); diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs index 74283a37afc..8b3d0546010 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #[derive(PartialEq, Eq)] struct NotParam; @@ -7,11 +7,11 @@ struct NotParam; #[derive(PartialEq, Eq)] struct CantParam(NotParam); -impl std::marker::ConstParamTy for CantParam {} -//~^ error: the trait `ConstParamTy` cannot be implemented for this type +impl std::marker::UnsizedConstParamTy for CantParam {} +//~^ error: the trait `ConstParamTy_` cannot be implemented for this type -#[derive(std::marker::ConstParamTy, Eq, PartialEq)] -//~^ error: the trait `ConstParamTy` cannot be implemented for this type +#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] +//~^ error: the trait `ConstParamTy_` cannot be implemented for this type struct CantParamDerive(NotParam); fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr index 52b65d6061a..808a569fcad 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr @@ -1,22 +1,22 @@ -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type - --> $DIR/const_param_ty_impl_bad_field.rs:10:36 +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/const_param_ty_impl_bad_field.rs:10:43 | LL | struct CantParam(NotParam); - | -------- this field does not implement `ConstParamTy` + | -------- this field does not implement `ConstParamTy_` LL | -LL | impl std::marker::ConstParamTy for CantParam {} - | ^^^^^^^^^ +LL | impl std::marker::UnsizedConstParamTy for CantParam {} + | ^^^^^^^^^ -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type --> $DIR/const_param_ty_impl_bad_field.rs:13:10 | -LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | struct CantParamDerive(NotParam); - | -------- this field does not implement `ConstParamTy` + | -------- this field does not implement `ConstParamTy_` | - = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `std::marker::UnsizedConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs index dfb8a36ec53..761a6387a24 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs @@ -1,22 +1,22 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #[derive(PartialEq, Eq)] struct ImplementsConstParamTy; -impl std::marker::ConstParamTy for ImplementsConstParamTy {} +impl std::marker::UnsizedConstParamTy for ImplementsConstParamTy {} struct CantParam(ImplementsConstParamTy); -impl std::marker::ConstParamTy for CantParam {} +impl std::marker::UnsizedConstParamTy for CantParam {} //~^ error: the type `CantParam` does not `#[derive(PartialEq)]` //~| the trait bound `CantParam: Eq` is not satisfied -#[derive(std::marker::ConstParamTy)] +#[derive(std::marker::UnsizedConstParamTy)] //~^ error: the type `CantParamDerive` does not `#[derive(PartialEq)]` //~| the trait bound `CantParamDerive: Eq` is not satisfied struct CantParamDerive(ImplementsConstParamTy); -fn check<T: std::marker::ConstParamTy>() {} +fn check<T: std::marker::UnsizedConstParamTy>() {} fn main() { check::<ImplementsConstParamTy>(); diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr index e213808cf7b..80d9942c591 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr @@ -1,10 +1,10 @@ error[E0277]: the trait bound `CantParam: Eq` is not satisfied - --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36 + --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:43 | -LL | impl std::marker::ConstParamTy for CantParam {} - | ^^^^^^^^^ the trait `Eq` is not implemented for `CantParam` +LL | impl std::marker::UnsizedConstParamTy for CantParam {} + | ^^^^^^^^^ the trait `Eq` is not implemented for `CantParam` | -note: required by a bound in `ConstParamTy` +note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL help: consider annotating `CantParam` with `#[derive(Eq)]` | @@ -13,23 +13,23 @@ LL | struct CantParam(ImplementsConstParamTy); | error[E0277]: the type `CantParam` does not `#[derive(PartialEq)]` - --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:36 + --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:43 | -LL | impl std::marker::ConstParamTy for CantParam {} - | ^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParam` +LL | impl std::marker::UnsizedConstParamTy for CantParam {} + | ^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParam` | -note: required by a bound in `ConstParamTy` +note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL error[E0277]: the trait bound `CantParamDerive: Eq` is not satisfied --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10 | -LL | #[derive(std::marker::ConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive` +LL | #[derive(std::marker::UnsizedConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive` | -note: required by a bound in `ConstParamTy` +note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL - = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `std::marker::UnsizedConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider annotating `CantParamDerive` with `#[derive(Eq)]` | LL + #[derive(Eq)] @@ -39,12 +39,12 @@ LL | struct CantParamDerive(ImplementsConstParamTy); error[E0277]: the type `CantParamDerive` does not `#[derive(PartialEq)]` --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10 | -LL | #[derive(std::marker::ConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParamDerive` +LL | #[derive(std::marker::UnsizedConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralPartialEq` is not implemented for `CantParamDerive` | -note: required by a bound in `ConstParamTy` +note: required by a bound in `UnsizedConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL - = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the derive macro `std::marker::UnsizedConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs index f2986f9cc60..236b3bc162a 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs @@ -1,5 +1,5 @@ #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] union Union { a: u8, @@ -12,10 +12,10 @@ impl PartialEq for Union { } impl Eq for Union {} -impl std::marker::ConstParamTy for Union {} -//~^ ERROR the type `Union` does not `#[derive(PartialEq)]` +impl std::marker::UnsizedConstParamTy for Union {} +//~^ ERROR the trait `ConstParamTy` may not be implemented for this type -#[derive(std::marker::ConstParamTy)] +#[derive(std::marker::UnsizedConstParamTy)] //~^ ERROR this trait cannot be derived for unions union UnionDerive { a: u8, @@ -28,5 +28,4 @@ impl PartialEq for UnionDerive { } impl Eq for UnionDerive {} - fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr index 4c937db6c3a..837c289c924 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr @@ -1,18 +1,14 @@ error: this trait cannot be derived for unions --> $DIR/const_param_ty_impl_union.rs:18:10 | -LL | #[derive(std::marker::ConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[derive(std::marker::UnsizedConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the type `Union` does not `#[derive(PartialEq)]` - --> $DIR/const_param_ty_impl_union.rs:15:36 +error: the trait `ConstParamTy` may not be implemented for this type + --> $DIR/const_param_ty_impl_union.rs:15:43 | -LL | impl std::marker::ConstParamTy for Union {} - | ^^^^^ the trait `StructuralPartialEq` is not implemented for `Union` - | -note: required by a bound in `ConstParamTy` - --> $SRC_DIR/core/src/marker.rs:LL:COL +LL | impl std::marker::UnsizedConstParamTy for Union {} + | ^^^^^ type is not a structure or enumeration error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs new file mode 100644 index 00000000000..6a553c2e085 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.rs @@ -0,0 +1,12 @@ +#![feature(adt_const_params, unsized_const_params)] +#![allow(incomplete_features)] + +use std::marker::{ConstParamTy_, UnsizedConstParamTy}; + +fn foo(a: &dyn ConstParamTy_) {} +//~^ ERROR: the trait `ConstParamTy_` + +fn bar(a: &dyn UnsizedConstParamTy) {} +//~^ ERROR: the trait `UnsizedConstParamTy` + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr new file mode 100644 index 00000000000..ba38f63d5df --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_object_safety.stderr @@ -0,0 +1,33 @@ +error[E0038]: the trait `ConstParamTy_` cannot be made into an object + --> $DIR/const_param_ty_object_safety.rs:6:12 + | +LL | fn foo(a: &dyn ConstParamTy_) {} + | ^^^^^^^^^^^^^^^^^ `ConstParamTy_` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: the trait cannot be made into an object because it uses `Self` as a type parameter +help: consider using an opaque type instead + | +LL | fn foo(a: &impl ConstParamTy_) {} + | ~~~~ + +error[E0038]: the trait `UnsizedConstParamTy` cannot be made into an object + --> $DIR/const_param_ty_object_safety.rs:9:12 + | +LL | fn bar(a: &dyn UnsizedConstParamTy) {} + | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` cannot be made into an object + | +note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety> + --> $SRC_DIR/core/src/cmp.rs:LL:COL + | + = note: the trait cannot be made into an object because it uses `Self` as a type parameter +help: consider using an opaque type instead + | +LL | fn bar(a: &impl UnsizedConstParamTy) {} + | ~~~~ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs index 0d1f023d565..7a4970c2e3c 100644 --- a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs +++ b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.rs @@ -1,18 +1,30 @@ // issue: rust-lang/rust/#83993 #![feature(adt_const_params)] -//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + fn bug<'a>() where for<'b> [(); { let x: &'b (); //~^ ERROR generic parameters may not be used in const operations 0 - }]: -{} + }]:, +{ +} -fn bad() where for<'b> [();{let _:&'b (); 0}]: Sized { } -//~^ ERROR generic parameters may not be used in const operations -fn good() where for<'b> [();{0}]: Sized { } +fn bad() +where + for<'b> [(); { + let _: &'b (); + //~^ ERROR generic parameters may not be used in const operations + 0 + }]: Sized, +{ +} +fn good() +where + for<'b> [(); { 0 }]: Sized, +{ +} pub fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr index a49dfc31916..b7e459511f1 100644 --- a/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr +++ b/tests/ui/const-generics/adt_const_params/index-oob-ice-83993.stderr @@ -8,22 +8,13 @@ LL | let x: &'b (); = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/index-oob-ice-83993.rs:14:36 + --> $DIR/index-oob-ice-83993.rs:18:17 | -LL | fn bad() where for<'b> [();{let _:&'b (); 0}]: Sized { } - | ^^ cannot perform const operation using `'b` +LL | let _: &'b (); + | ^^ cannot perform const operation using `'b` | = note: lifetime parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/index-oob-ice-83993.rs:3:12 - | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information - = note: `#[warn(incomplete_features)]` on by default - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs index 9f05c53eef0..3a283442a0b 100644 --- a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs +++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs @@ -4,15 +4,18 @@ use std::marker::ConstParamTy; #[derive(ConstParamTy)] -//~^ the trait `ConstParamTy` cannot be implemented for this ty +//~^ the trait `ConstParamTy_` cannot be implemented for this ty +//~| the trait `ConstParamTy_` cannot be implemented for this ty struct Foo([*const u8; 1]); #[derive(ConstParamTy)] -//~^ the trait `ConstParamTy` cannot be implemented for this ty +//~^ the trait `ConstParamTy_` cannot be implemented for this ty +//~| the trait `ConstParamTy_` cannot be implemented for this ty struct Foo2([*mut u8; 1]); #[derive(ConstParamTy)] -//~^ the trait `ConstParamTy` cannot be implemented for this ty +//~^ the trait `ConstParamTy_` cannot be implemented for this ty +//~| the trait `ConstParamTy_` cannot be implemented for this ty struct Foo3([fn(); 1]); fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr index 9e772e8d55d..c2520f1d103 100644 --- a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr +++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr @@ -1,51 +1,99 @@ -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type --> $DIR/nested_bad_const_param_ty.rs:6:10 | LL | #[derive(ConstParamTy)] | ^^^^^^^^^^^^ -LL | +... LL | struct Foo([*const u8; 1]); - | -------------- this field does not implement `ConstParamTy` + | -------------- this field does not implement `ConstParamTy_` | -note: the `ConstParamTy` impl for `[*const u8; 1]` requires that `*const u8: ConstParamTy` - --> $DIR/nested_bad_const_param_ty.rs:8:12 +note: the `ConstParamTy_` impl for `[*const u8; 1]` requires that `*const u8: ConstParamTy_` + --> $DIR/nested_bad_const_param_ty.rs:9:12 | LL | struct Foo([*const u8; 1]); | ^^^^^^^^^^^^^^ = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type - --> $DIR/nested_bad_const_param_ty.rs:10:10 +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:11:10 | LL | #[derive(ConstParamTy)] | ^^^^^^^^^^^^ -LL | +... LL | struct Foo2([*mut u8; 1]); - | ------------ this field does not implement `ConstParamTy` + | ------------ this field does not implement `ConstParamTy_` | -note: the `ConstParamTy` impl for `[*mut u8; 1]` requires that `*mut u8: ConstParamTy` - --> $DIR/nested_bad_const_param_ty.rs:12:13 +note: the `ConstParamTy_` impl for `[*mut u8; 1]` requires that `*mut u8: ConstParamTy_` + --> $DIR/nested_bad_const_param_ty.rs:14:13 | LL | struct Foo2([*mut u8; 1]); | ^^^^^^^^^^^^ = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0204]: the trait `ConstParamTy` cannot be implemented for this type - --> $DIR/nested_bad_const_param_ty.rs:14:10 +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:16:10 | LL | #[derive(ConstParamTy)] | ^^^^^^^^^^^^ -LL | +... LL | struct Foo3([fn(); 1]); - | --------- this field does not implement `ConstParamTy` + | --------- this field does not implement `ConstParamTy_` | -note: the `ConstParamTy` impl for `[fn(); 1]` requires that `fn(): ConstParamTy` - --> $DIR/nested_bad_const_param_ty.rs:16:13 +note: the `ConstParamTy_` impl for `[fn(); 1]` requires that `fn(): ConstParamTy_` + --> $DIR/nested_bad_const_param_ty.rs:19:13 | LL | struct Foo3([fn(); 1]); | ^^^^^^^^^ = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:6:10 + | +LL | #[derive(ConstParamTy)] + | ^^^^^^^^^^^^ +... +LL | struct Foo([*const u8; 1]); + | -------------- this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `[*const u8; 1]` requires that `*const u8: UnsizedConstParamTy` + --> $DIR/nested_bad_const_param_ty.rs:9:12 + | +LL | struct Foo([*const u8; 1]); + | ^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:11:10 + | +LL | #[derive(ConstParamTy)] + | ^^^^^^^^^^^^ +... +LL | struct Foo2([*mut u8; 1]); + | ------------ this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `[*mut u8; 1]` requires that `*mut u8: UnsizedConstParamTy` + --> $DIR/nested_bad_const_param_ty.rs:14:13 + | +LL | struct Foo2([*mut u8; 1]); + | ^^^^^^^^^^^^ + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/nested_bad_const_param_ty.rs:16:10 + | +LL | #[derive(ConstParamTy)] + | ^^^^^^^^^^^^ +... +LL | struct Foo3([fn(); 1]); + | --------- this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `[fn(); 1]` requires that `fn(): UnsizedConstParamTy` + --> $DIR/nested_bad_const_param_ty.rs:19:13 + | +LL | struct Foo3([fn(); 1]); + | ^^^^^^^^^ + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs index c55f3dcec68..f28bebf85db 100644 --- a/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs +++ b/tests/ui/const-generics/adt_const_params/opaque_type_with_non-universal_region_substs_ice-111911.rs @@ -3,7 +3,7 @@ // issues rust-lang/rust#111911 // test for ICE opaque type with non-universal region substs -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub async fn foo<const X: &'static str>() {} diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs new file mode 100644 index 00000000000..a1ee1c4cdd5 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs @@ -0,0 +1,11 @@ +#![feature(adt_const_params, unsized_const_params)] +#![allow(incomplete_features)] + +use std::marker::UnsizedConstParamTy; + +struct Foo; + +impl UnsizedConstParamTy for &'static Foo {} +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr new file mode 100644 index 00000000000..5ca8e6c7516 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr @@ -0,0 +1,9 @@ +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/reference_pointee_is_const_param-1.rs:8:30 + | +LL | impl UnsizedConstParamTy for &'static Foo {} + | ^^^^^^^^^^^^ this field does not implement `ConstParamTy_` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs new file mode 100644 index 00000000000..ac1b522f469 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs @@ -0,0 +1,27 @@ +#![feature(adt_const_params, unsized_const_params)] +#![allow(incomplete_features)] + +// Regression test for #119299 + +use std::marker::UnsizedConstParamTy; + +#[derive(Eq, PartialEq)] +struct ConstStrU(*const u8, usize); + +impl UnsizedConstParamTy for &'static ConstStrU {} +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type + +impl ConstStrU { + const fn from_bytes(bytes: &'static [u8]) -> Self { + Self(bytes.as_ptr(), bytes.len()) + } +} + +const fn chars_s<const S: &'static ConstStrU>() -> [char; 3] { + ['a', 'b', 'c'] +} + +fn main() { + const A: &'static ConstStrU = &ConstStrU::from_bytes(b"abc"); + chars_s::<A>(); +} diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr new file mode 100644 index 00000000000..5e5f6cc642d --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr @@ -0,0 +1,9 @@ +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/reference_pointee_is_const_param-2.rs:11:30 + | +LL | impl UnsizedConstParamTy for &'static ConstStrU {} + | ^^^^^^^^^^^^^^^^^^ this field does not implement `ConstParamTy_` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs index 0d2e65c45ea..33988bc0678 100644 --- a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs +++ b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.rs @@ -8,9 +8,8 @@ fn uwu_0<const N: &'static mut ()>() {} //~| HELP: add `#![feature(adt_const_params)]` //~| HELP: add `#![feature(adt_const_params)]` //~| HELP: add `#![feature(adt_const_params)]` -//~| HELP: add `#![feature(adt_const_params)]` -//~| HELP: add `#![feature(adt_const_params)]` -//~| HELP: add `#![feature(adt_const_params)]` +//~| HELP: add `#![feature(unsized_const_params)]` +//~| HELP: add `#![feature(unsized_const_params)]` // Needs the feature but can be used, so suggest adding the feature. fn owo_0<const N: &'static u32>() {} diff --git a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr index cd4349623d7..aafc0640dd2 100644 --- a/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr +++ b/tests/ui/const-generics/adt_const_params/suggest_feature_only_when_possible.stderr @@ -7,7 +7,7 @@ LL | fn uwu_0<const N: &'static mut ()>() {} = note: the only supported types are integers, `bool` and `char` error: `&'static u32` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:16:19 + --> $DIR/suggest_feature_only_when_possible.rs:15:19 | LL | fn owo_0<const N: &'static u32>() {} | ^^^^^^^^^^^^ @@ -17,9 +17,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `Meow` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:24:20 + --> $DIR/suggest_feature_only_when_possible.rs:23:20 | LL | fn meow_0<const N: Meow>() {} | ^^^^ @@ -31,7 +35,7 @@ LL + #![feature(adt_const_params)] | error: `&'static Meow` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:26:20 + --> $DIR/suggest_feature_only_when_possible.rs:25:20 | LL | fn meow_1<const N: &'static Meow>() {} | ^^^^^^^^^^^^^ @@ -41,45 +45,37 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `[Meow; 100]` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:28:20 + --> $DIR/suggest_feature_only_when_possible.rs:27:20 | LL | fn meow_2<const N: [Meow; 100]>() {} | ^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | error: `(Meow, u8)` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:30:20 + --> $DIR/suggest_feature_only_when_possible.rs:29:20 | LL | fn meow_3<const N: (Meow, u8)>() {} | ^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | error: `(Meow, String)` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:35:20 + --> $DIR/suggest_feature_only_when_possible.rs:34:20 | LL | fn meow_4<const N: (Meow, String)>() {} | ^^^^^^^^^^^^^^ | = note: the only supported types are integers, `bool` and `char` -help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types - | -LL + #![feature(adt_const_params)] - | error: `String` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:39:19 + --> $DIR/suggest_feature_only_when_possible.rs:38:19 | LL | fn nya_0<const N: String>() {} | ^^^^^^ @@ -87,7 +83,7 @@ LL | fn nya_0<const N: String>() {} = note: the only supported types are integers, `bool` and `char` error: `Vec<u32>` is forbidden as the type of a const generic parameter - --> $DIR/suggest_feature_only_when_possible.rs:41:19 + --> $DIR/suggest_feature_only_when_possible.rs:40:19 | LL | fn nya_1<const N: Vec<u32>>() {} | ^^^^^^^^ diff --git a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs new file mode 100644 index 00000000000..b0934508399 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs @@ -0,0 +1,13 @@ +#![feature(adt_const_params, unsized_const_params)] +#![allow(incomplete_features)] + +use std::marker::UnsizedConstParamTy; + +trait Trait {} + +impl UnsizedConstParamTy for dyn Trait {} +//~^ ERROR: the trait `ConstParamTy` may not be implemented for this type + +fn foo<const N: dyn Trait>() {} + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr new file mode 100644 index 00000000000..9933ba6e335 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr @@ -0,0 +1,8 @@ +error: the trait `ConstParamTy` may not be implemented for this type + --> $DIR/trait_objects_as_a_const_generic.rs:8:30 + | +LL | impl UnsizedConstParamTy for dyn Trait {} + | ^^^^^^^^^ type is not a structure or enumeration + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.rs b/tests/ui/const-generics/adt_const_params/unsized_field-1.rs new file mode 100644 index 00000000000..f6e5bd6e355 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.rs @@ -0,0 +1,20 @@ +//@ aux-build:unsized_const_param.rs +#![feature(adt_const_params)] + +extern crate unsized_const_param; + +use std::marker::ConstParamTy; + +#[derive(ConstParamTy, Eq, PartialEq)] +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type +struct A([u8]); + +#[derive(ConstParamTy, Eq, PartialEq)] +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type +struct B(&'static [u8]); + +#[derive(ConstParamTy, Eq, PartialEq)] +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type +struct C(unsized_const_param::Foo); + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr new file mode 100644 index 00000000000..7a4f9b99c63 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr @@ -0,0 +1,36 @@ +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/unsized_field-1.rs:8:10 + | +LL | #[derive(ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^ +LL | +LL | struct A([u8]); + | ---- this field does not implement `ConstParamTy_` + | + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/unsized_field-1.rs:12:10 + | +LL | #[derive(ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^ +LL | +LL | struct B(&'static [u8]); + | ------------- this field does not implement `ConstParamTy_` + | + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/unsized_field-1.rs:16:10 + | +LL | #[derive(ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^ +LL | +LL | struct C(unsized_const_param::Foo); + | ------------------------ this field does not implement `ConstParamTy_` + | + = note: this error originates in the derive macro `ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-2.rs b/tests/ui/const-generics/adt_const_params/unsized_field-2.rs new file mode 100644 index 00000000000..e4a3a481b4e --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/unsized_field-2.rs @@ -0,0 +1,14 @@ +//@ aux-build:unsized_const_param.rs +#![feature(adt_const_params, unsized_const_params)] +//~^ WARN: the feature `unsized_const_params` is incomplete + +extern crate unsized_const_param; + +#[derive(std::marker::ConstParamTy, Eq, PartialEq)] +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type +struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + +#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] +struct B(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr new file mode 100644 index 00000000000..15acece538f --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr @@ -0,0 +1,28 @@ +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unsized_field-2.rs:2:30 + | +LL | #![feature(adt_const_params, unsized_const_params)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type + --> $DIR/unsized_field-2.rs:7:10 + | +LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + | ---------------------------------------------------------- this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `GenericNotUnsizedParam<&'static [u8]>` requires that `&'static [u8]: ConstParamTy_` + --> $DIR/unsized_field-2.rs:9:10 + | +LL | struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr index 1c81b14f8f5..62267224738 100644 --- a/tests/ui/const-generics/const-param-elided-lifetime.min.stderr +++ b/tests/ui/const-generics/const-param-elided-lifetime.min.stderr @@ -39,6 +39,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&u8` is forbidden as the type of a const generic parameter --> $DIR/const-param-elided-lifetime.rs:14:15 @@ -51,6 +55,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&u8` is forbidden as the type of a const generic parameter --> $DIR/const-param-elided-lifetime.rs:22:15 @@ -63,6 +71,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&u8` is forbidden as the type of a const generic parameter --> $DIR/const-param-elided-lifetime.rs:26:17 @@ -75,6 +87,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&u8` is forbidden as the type of a const generic parameter --> $DIR/const-param-elided-lifetime.rs:17:21 @@ -87,6 +103,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 10 previous errors diff --git a/tests/ui/const-generics/const-param-elided-lifetime.rs b/tests/ui/const-generics/const-param-elided-lifetime.rs index ef1eecb59be..e75073de98d 100644 --- a/tests/ui/const-generics/const-param-elided-lifetime.rs +++ b/tests/ui/const-generics/const-param-elided-lifetime.rs @@ -3,7 +3,7 @@ // elided lifetimes within the type of a const generic parameters to be 'static, like elided // lifetimes within const/static items. //@ revisions: full min -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] struct A<const N: &u8>; @@ -12,8 +12,8 @@ struct A<const N: &u8>; trait B {} impl<const N: &u8> A<N> { -//~^ ERROR `&` without an explicit lifetime name cannot be used here -//[min]~^^ ERROR `&u8` is forbidden + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //[min]~^^ ERROR `&u8` is forbidden fn foo<const M: &u8>(&self) {} //~^ ERROR `&` without an explicit lifetime name cannot be used here //[min]~^^ ERROR `&u8` is forbidden diff --git a/tests/ui/const-generics/const-param-with-additional-obligations.rs b/tests/ui/const-generics/const-param-with-additional-obligations.rs index f53cf85cdd3..98097e86c7d 100644 --- a/tests/ui/const-generics/const-param-with-additional-obligations.rs +++ b/tests/ui/const-generics/const-param-with-additional-obligations.rs @@ -1,14 +1,14 @@ -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::ConstParamTy; +use std::marker::UnsizedConstParamTy; #[derive(Eq, PartialEq)] struct Foo<T>(T); trait Other {} -impl<T> ConstParamTy for Foo<T> where T: Other + ConstParamTy {} +impl<T> UnsizedConstParamTy for Foo<T> where T: Other + UnsizedConstParamTy {} fn foo<const N: Foo<u8>>() {} //~^ ERROR `Foo<u8>` must implement `ConstParamTy` to be used as the type of a const generic parameter diff --git a/tests/ui/const-generics/float-generic.adt_const_params.stderr b/tests/ui/const-generics/float-generic.adt_const_params.stderr index cae4806368a..1a7c19ba4be 100644 --- a/tests/ui/const-generics/float-generic.adt_const_params.stderr +++ b/tests/ui/const-generics/float-generic.adt_const_params.stderr @@ -1,5 +1,5 @@ error[E0741]: `f32` is forbidden as the type of a const generic parameter - --> $DIR/float-generic.rs:5:17 + --> $DIR/float-generic.rs:7:17 | LL | fn foo<const F: f32>() {} | ^^^ diff --git a/tests/ui/const-generics/float-generic.full.stderr b/tests/ui/const-generics/float-generic.full.stderr new file mode 100644 index 00000000000..1a7c19ba4be --- /dev/null +++ b/tests/ui/const-generics/float-generic.full.stderr @@ -0,0 +1,9 @@ +error[E0741]: `f32` is forbidden as the type of a const generic parameter + --> $DIR/float-generic.rs:7:17 + | +LL | fn foo<const F: f32>() {} + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/float-generic.rs b/tests/ui/const-generics/float-generic.rs index aaf63a93d70..f92e1667701 100644 --- a/tests/ui/const-generics/float-generic.rs +++ b/tests/ui/const-generics/float-generic.rs @@ -1,4 +1,6 @@ -//@ revisions: simple adt_const_params +//@ revisions: simple adt_const_params full +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] +#![cfg_attr(full, allow(incomplete_features))] #![cfg_attr(adt_const_params, feature(adt_const_params))] #![cfg_attr(adt_const_params, allow(incomplete_features))] diff --git a/tests/ui/const-generics/float-generic.simple.stderr b/tests/ui/const-generics/float-generic.simple.stderr index eccf9059ee3..2999bce32d6 100644 --- a/tests/ui/const-generics/float-generic.simple.stderr +++ b/tests/ui/const-generics/float-generic.simple.stderr @@ -1,5 +1,5 @@ error: `f32` is forbidden as the type of a const generic parameter - --> $DIR/float-generic.rs:5:17 + --> $DIR/float-generic.rs:7:17 | LL | fn foo<const F: f32>() {} | ^^^ diff --git a/tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr b/tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr new file mode 100644 index 00000000000..fd9346a533e --- /dev/null +++ b/tests/ui/const-generics/fn-const-param-call.adt_const_params.stderr @@ -0,0 +1,15 @@ +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-call.rs:13:25 + | +LL | struct Wrapper<const F: fn() -> u32>; + | ^^^^^^^^^^^ + +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-call.rs:15:15 + | +LL | impl<const F: fn() -> u32> Wrapper<F> { + | ^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/fn-const-param-call.full.stderr b/tests/ui/const-generics/fn-const-param-call.full.stderr index b55c2449858..fd9346a533e 100644 --- a/tests/ui/const-generics/fn-const-param-call.full.stderr +++ b/tests/ui/const-generics/fn-const-param-call.full.stderr @@ -1,11 +1,11 @@ error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-call.rs:11:25 + --> $DIR/fn-const-param-call.rs:13:25 | LL | struct Wrapper<const F: fn() -> u32>; | ^^^^^^^^^^^ error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-call.rs:13:15 + --> $DIR/fn-const-param-call.rs:15:15 | LL | impl<const F: fn() -> u32> Wrapper<F> { | ^^^^^^^^^^^ diff --git a/tests/ui/const-generics/fn-const-param-call.min.stderr b/tests/ui/const-generics/fn-const-param-call.min.stderr index 2d316fba1e9..d37766b28c9 100644 --- a/tests/ui/const-generics/fn-const-param-call.min.stderr +++ b/tests/ui/const-generics/fn-const-param-call.min.stderr @@ -1,5 +1,5 @@ error: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-call.rs:11:25 + --> $DIR/fn-const-param-call.rs:13:25 | LL | struct Wrapper<const F: fn() -> u32>; | ^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | struct Wrapper<const F: fn() -> u32>; = note: the only supported types are integers, `bool` and `char` error: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-call.rs:13:15 + --> $DIR/fn-const-param-call.rs:15:15 | LL | impl<const F: fn() -> u32> Wrapper<F> { | ^^^^^^^^^^^ diff --git a/tests/ui/const-generics/fn-const-param-call.rs b/tests/ui/const-generics/fn-const-param-call.rs index ce780143178..d536c240239 100644 --- a/tests/ui/const-generics/fn-const-param-call.rs +++ b/tests/ui/const-generics/fn-const-param-call.rs @@ -1,8 +1,10 @@ // Check that functions cannot be used as const parameters. -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] fn function() -> u32 { 17 @@ -11,7 +13,7 @@ fn function() -> u32 { struct Wrapper<const F: fn() -> u32>; //~ ERROR: using function pointers as const generic parameters impl<const F: fn() -> u32> Wrapper<F> { -//~^ ERROR: using function pointers as const generic parameters + //~^ ERROR: using function pointers as const generic parameters fn call() -> u32 { F() } diff --git a/tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr b/tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr new file mode 100644 index 00000000000..54f3bff172a --- /dev/null +++ b/tests/ui/const-generics/fn-const-param-infer.adt_const_params.stderr @@ -0,0 +1,30 @@ +error[E0741]: using function pointers as const generic parameters is forbidden + --> $DIR/fn-const-param-infer.rs:8:25 + | +LL | struct Checked<const F: fn(usize) -> bool>; + | ^^^^^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/fn-const-param-infer.rs:33:25 + | +LL | let _ = Checked::<{ generic_arg::<u32> }>; + | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item + | + = note: expected fn pointer `fn(usize) -> _` + found fn item `fn(u32) -> _ {generic_arg::<u32>}` + +error[E0282]: type annotations needed + --> $DIR/fn-const-param-infer.rs:35:23 + | +LL | let _ = Checked::<generic>; + | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `generic` + | +help: consider specifying the generic argument + | +LL | let _ = Checked::<generic::<T>>; + | +++++ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0282, E0308, E0741. +For more information about an error, try `rustc --explain E0282`. diff --git a/tests/ui/const-generics/fn-const-param-infer.full.stderr b/tests/ui/const-generics/fn-const-param-infer.full.stderr index 753558636e1..54f3bff172a 100644 --- a/tests/ui/const-generics/fn-const-param-infer.full.stderr +++ b/tests/ui/const-generics/fn-const-param-infer.full.stderr @@ -1,20 +1,20 @@ error[E0741]: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-infer.rs:6:25 + --> $DIR/fn-const-param-infer.rs:8:25 | LL | struct Checked<const F: fn(usize) -> bool>; | ^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:23:24 + --> $DIR/fn-const-param-infer.rs:33:25 | -LL | let _ = Checked::<{generic_arg::<u32>}>; - | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item +LL | let _ = Checked::<{ generic_arg::<u32> }>; + | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item | = note: expected fn pointer `fn(usize) -> _` found fn item `fn(u32) -> _ {generic_arg::<u32>}` error[E0282]: type annotations needed - --> $DIR/fn-const-param-infer.rs:25:23 + --> $DIR/fn-const-param-infer.rs:35:23 | LL | let _ = Checked::<generic>; | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `generic` diff --git a/tests/ui/const-generics/fn-const-param-infer.min.stderr b/tests/ui/const-generics/fn-const-param-infer.min.stderr index 01e224f8d9c..4da503d344a 100644 --- a/tests/ui/const-generics/fn-const-param-infer.min.stderr +++ b/tests/ui/const-generics/fn-const-param-infer.min.stderr @@ -1,5 +1,5 @@ error: using function pointers as const generic parameters is forbidden - --> $DIR/fn-const-param-infer.rs:6:25 + --> $DIR/fn-const-param-infer.rs:8:25 | LL | struct Checked<const F: fn(usize) -> bool>; | ^^^^^^^^^^^^^^^^^ @@ -7,16 +7,16 @@ LL | struct Checked<const F: fn(usize) -> bool>; = note: the only supported types are integers, `bool` and `char` error[E0308]: mismatched types - --> $DIR/fn-const-param-infer.rs:23:24 + --> $DIR/fn-const-param-infer.rs:33:25 | -LL | let _ = Checked::<{generic_arg::<u32>}>; - | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item +LL | let _ = Checked::<{ generic_arg::<u32> }>; + | ^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item | = note: expected fn pointer `fn(usize) -> _` found fn item `fn(u32) -> _ {generic_arg::<u32>}` error[E0282]: type annotations needed - --> $DIR/fn-const-param-infer.rs:25:23 + --> $DIR/fn-const-param-infer.rs:35:23 | LL | let _ = Checked::<generic>; | ^^^^^^^ cannot infer type of the type parameter `T` declared on the function `generic` diff --git a/tests/ui/const-generics/fn-const-param-infer.rs b/tests/ui/const-generics/fn-const-param-infer.rs index ed0bb9f7217..5f1958df26e 100644 --- a/tests/ui/const-generics/fn-const-param-infer.rs +++ b/tests/ui/const-generics/fn-const-param-infer.rs @@ -1,17 +1,27 @@ -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] struct Checked<const F: fn(usize) -> bool>; //~^ ERROR: using function pointers as const generic parameters -fn not_one(val: usize) -> bool { val != 1 } -fn not_two(val: usize) -> bool { val != 2 } +fn not_one(val: usize) -> bool { + val != 1 +} +fn not_two(val: usize) -> bool { + val != 2 +} -fn generic_arg<T>(val: T) -> bool { true } +fn generic_arg<T>(val: T) -> bool { + true +} -fn generic<T>(val: usize) -> bool { val != 1 } +fn generic<T>(val: usize) -> bool { + val != 1 +} fn main() { let _: Option<Checked<not_one>> = None; @@ -19,11 +29,11 @@ fn main() { let _: Checked<not_one> = Checked::<not_two>; let _ = Checked::<generic_arg>; - let _ = Checked::<{generic_arg::<usize>}>; - let _ = Checked::<{generic_arg::<u32>}>; //~ ERROR: mismatched types + let _ = Checked::<{ generic_arg::<usize> }>; + let _ = Checked::<{ generic_arg::<u32> }>; //~ ERROR: mismatched types let _ = Checked::<generic>; //~ ERROR: type annotations needed - let _ = Checked::<{generic::<u16>}>; - let _: Checked<{generic::<u16>}> = Checked::<{generic::<u16>}>; - let _: Checked<{generic::<u32>}> = Checked::<{generic::<u16>}>; + let _ = Checked::<{ generic::<u16> }>; + let _: Checked<{ generic::<u16> }> = Checked::<{ generic::<u16> }>; + let _: Checked<{ generic::<u32> }> = Checked::<{ generic::<u16> }>; } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-100360.rs b/tests/ui/const-generics/generic_const_exprs/issue-100360.rs index b7e677a4a1e..37f015d5e0f 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-100360.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-100360.rs @@ -1,7 +1,7 @@ //@ check-pass // (this requires debug assertions) -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] fn foo<const B: &'static bool>(arg: &'static bool) -> bool { diff --git a/tests/ui/const-generics/generic_const_exprs/issue-89851.rs b/tests/ui/const-generics/generic_const_exprs/issue-89851.rs index 78189c5225c..f93ba30856d 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-89851.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-89851.rs @@ -1,7 +1,7 @@ //@ check-pass // (this requires debug assertions) -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub const BAR: () = ice::<"">(); diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs index 5a6565fe2f1..443d0a2fe87 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.rs @@ -1,7 +1,7 @@ //@ check-pass -#![feature(adt_const_params, generic_const_exprs)] -//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] +//~^ WARN the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] //~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] pub struct Changes<const CHANGES: &'static [&'static str]> @@ -16,9 +16,7 @@ where [(); CHANGES.len()]:, { pub const fn new() -> Self { - Self { - changes: [0; CHANGES.len()], - } + Self { changes: [0; CHANGES.len()] } } } diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr index 1cceaece715..b6b297593a2 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-1.stderr @@ -1,17 +1,17 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-1.rs:3:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-97047-ice-1.rs:3:30 | -LL | #![feature(adt_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information = note: `#[warn(incomplete_features)]` on by default warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-1.rs:3:30 + --> $DIR/issue-97047-ice-1.rs:3:52 | -LL | #![feature(adt_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ | = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs index 1338f40208c..6a91b522567 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.rs @@ -1,7 +1,7 @@ //@ check-pass -#![feature(adt_const_params, generic_const_exprs)] -//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] +//~^ WARN the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] //~^^ WARN the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] pub struct Changes<const CHANGES: &'static [&'static str]> diff --git a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr index 774e842bcbe..c0c7dcc79dc 100644 --- a/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr +++ b/tests/ui/const-generics/generic_const_exprs/issue-97047-ice-2.stderr @@ -1,17 +1,17 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-2.rs:3:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-97047-ice-2.rs:3:30 | -LL | #![feature(adt_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information = note: `#[warn(incomplete_features)]` on by default warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-97047-ice-2.rs:3:30 + --> $DIR/issue-97047-ice-2.rs:3:52 | -LL | #![feature(adt_const_params, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params, generic_const_exprs)] + | ^^^^^^^^^^^^^^^^^^^ | = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information diff --git a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs index 5673f1dd073..ffa9d960e04 100644 --- a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs +++ b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.rs @@ -7,7 +7,8 @@ pub fn foo() where for<const N: usize = { const fn bar() {} bar(); 1 }> ():, - //~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~^ ERROR late-bound const parameters cannot be used currently + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders {} fn main() {} diff --git a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr index 5924a673da9..814022f26b9 100644 --- a/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr +++ b/tests/ui/const-generics/generic_const_exprs/no-entry-found-for-key-ice-gce-nlb-113133.stderr @@ -1,8 +1,14 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/no-entry-found-for-key-ice-gce-nlb-113133.rs:9:15 + | +LL | for<const N: usize = { const fn bar() {} bar(); 1 }> ():, + | ^ + error: defaults for generic parameters are not allowed in `for<...>` binders --> $DIR/no-entry-found-for-key-ice-gce-nlb-113133.rs:9:9 | LL | for<const N: usize = { const fn bar() {} bar(); 1 }> ():, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr index 5e4acd80e93..2a6d9f53317 100644 --- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr +++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr @@ -1,14 +1,14 @@ error: generic parameters may not be used in const operations - --> $DIR/intrinsics-type_name-as-const-argument.rs:15:44 + --> $DIR/intrinsics-type_name-as-const-argument.rs:14:45 | -LL | T: Trait<{std::intrinsics::type_name::<T>()}> - | ^ cannot perform const operation using `T` +LL | T: Trait<{ std::intrinsics::type_name::<T>() }>, + | ^ cannot perform const operation using `T` | = note: type parameters may not be used in const expressions = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions error: `&'static str` is forbidden as the type of a const generic parameter - --> $DIR/intrinsics-type_name-as-const-argument.rs:10:22 + --> $DIR/intrinsics-type_name-as-const-argument.rs:9:22 | LL | trait Trait<const S: &'static str> {} | ^^^^^^^^^^^^ @@ -18,6 +18,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs index 02e6d27a27e..79c20fe81e3 100644 --- a/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs +++ b/tests/ui/const-generics/intrinsics-type_name-as-const-argument.rs @@ -2,8 +2,7 @@ //@ revisions: full min #![cfg_attr(full, allow(incomplete_features))] -#![cfg_attr(full, feature(adt_const_params, generic_const_exprs))] - +#![cfg_attr(full, feature(adt_const_params, unsized_const_params, generic_const_exprs))] #![feature(core_intrinsics)] #![feature(const_type_name)] @@ -12,10 +11,10 @@ trait Trait<const S: &'static str> {} struct Bug<T> where - T: Trait<{std::intrinsics::type_name::<T>()}> + T: Trait<{ std::intrinsics::type_name::<T>() }>, //[min]~^ ERROR generic parameters may not be used in const operations { - t: T + t: T, } fn main() {} diff --git a/tests/ui/const-generics/issue-66451.rs b/tests/ui/const-generics/issue-66451.rs index c8d5515e987..0b8693e0e67 100644 --- a/tests/ui/const-generics/issue-66451.rs +++ b/tests/ui/const-generics/issue-66451.rs @@ -1,30 +1,20 @@ -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::ConstParamTy; +use std::marker::UnsizedConstParamTy; -#[derive(Debug, PartialEq, Eq, ConstParamTy)] +#[derive(Debug, PartialEq, Eq, UnsizedConstParamTy)] struct Foo { value: i32, nested: &'static Bar<i32>, } -#[derive(Debug, PartialEq, Eq, ConstParamTy)] +#[derive(Debug, PartialEq, Eq, UnsizedConstParamTy)] struct Bar<T>(T); struct Test<const F: Foo>; fn main() { - let x: Test<{ - Foo { - value: 3, - nested: &Bar(4), - } - }> = Test; - let y: Test<{ - Foo { - value: 3, - nested: &Bar(5), - } - }> = x; //~ ERROR mismatched types + let x: Test<{ Foo { value: 3, nested: &Bar(4) } }> = Test; + let y: Test<{ Foo { value: 3, nested: &Bar(5) } }> = x; //~ ERROR mismatched types } diff --git a/tests/ui/const-generics/issue-66451.stderr b/tests/ui/const-generics/issue-66451.stderr index 404e3839bca..63d193e1bca 100644 --- a/tests/ui/const-generics/issue-66451.stderr +++ b/tests/ui/const-generics/issue-66451.stderr @@ -1,16 +1,10 @@ error[E0308]: mismatched types - --> $DIR/issue-66451.rs:29:10 + --> $DIR/issue-66451.rs:19:58 | -LL | let y: Test<{ - | ____________- -LL | | Foo { -LL | | value: 3, -LL | | nested: &Bar(5), -LL | | } -LL | | }> = x; - | | - ^ expected `Foo { value: 3, nested: &Bar::<i32>(5) }`, found `Foo { value: 3, nested: &Bar::<i32>(4) }` - | |______| - | expected due to this +LL | let y: Test<{ Foo { value: 3, nested: &Bar(5) } }> = x; + | ------------------------------------------- ^ expected `Foo { value: 3, nested: &Bar::<i32>(5) }`, found `Foo { value: 3, nested: &Bar::<i32>(4) }` + | | + | expected due to this | = note: expected struct `Test<Foo { value: 3, nested: &Bar::<i32>(5) }>` found struct `Test<Foo { value: 3, nested: &Bar::<i32>(4) }>` diff --git a/tests/ui/const-generics/issue-70408.rs b/tests/ui/const-generics/issue-70408.rs index e74bcf945a5..ea7a57d3b2f 100644 --- a/tests/ui/const-generics/issue-70408.rs +++ b/tests/ui/const-generics/issue-70408.rs @@ -1,6 +1,6 @@ //@ build-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] { diff --git a/tests/ui/const-generics/issue-80471.rs b/tests/ui/const-generics/issue-80471.rs index fa6f1fde435..20d92092b9f 100644 --- a/tests/ui/const-generics/issue-80471.rs +++ b/tests/ui/const-generics/issue-80471.rs @@ -1,5 +1,4 @@ #![feature(adt_const_params)] -//~^ WARN the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features] #[derive(PartialEq, Eq)] enum Nat { diff --git a/tests/ui/const-generics/issue-80471.stderr b/tests/ui/const-generics/issue-80471.stderr index b21ad3aec79..a8514c5cc07 100644 --- a/tests/ui/const-generics/issue-80471.stderr +++ b/tests/ui/const-generics/issue-80471.stderr @@ -1,14 +1,5 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-80471.rs:1:12 - | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information - = note: `#[warn(incomplete_features)]` on by default - error[E0741]: `Nat` must implement `ConstParamTy` to be used as the type of a const generic parameter - --> $DIR/issue-80471.rs:10:17 + --> $DIR/issue-80471.rs:9:17 | LL | fn foo<const N: Nat>() {} | ^^^ @@ -19,6 +10,6 @@ LL + #[derive(ConstParamTy)] LL | enum Nat { | -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/issues/issue-100313.rs b/tests/ui/const-generics/issues/issue-100313.rs index 4e9d3626aa8..e07fde76a4a 100644 --- a/tests/ui/const-generics/issues/issue-100313.rs +++ b/tests/ui/const-generics/issues/issue-100313.rs @@ -1,10 +1,10 @@ #![allow(incomplete_features)] #![feature(const_mut_refs)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] struct T<const B: &'static bool>; -impl <const B: &'static bool> T<B> { +impl<const B: &'static bool> T<B> { const fn set_false(&self) { unsafe { *(B as *const bool as *mut bool) = false; @@ -14,7 +14,7 @@ impl <const B: &'static bool> T<B> { } const _: () = { - let x = T::<{&true}>; + let x = T::<{ &true }>; x.set_false(); }; diff --git a/tests/ui/const-generics/issues/issue-105821.rs b/tests/ui/const-generics/issues/issue-105821.rs index ecbae4d9f35..3092893837a 100644 --- a/tests/ui/const-generics/issues/issue-105821.rs +++ b/tests/ui/const-generics/issues/issue-105821.rs @@ -4,7 +4,7 @@ // a failing test, we just started masking the bug. #![allow(incomplete_features)] -#![feature(adt_const_params, generic_const_exprs)] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(dead_code)] const fn catone<const M: usize>(_a: &[u8; M]) -> [u8; M + 1] diff --git a/tests/ui/const-generics/issues/issue-56445-1.min.stderr b/tests/ui/const-generics/issues/issue-56445-1.min.stderr index 580542bb6da..ff0a1bfc0b5 100644 --- a/tests/ui/const-generics/issues/issue-56445-1.min.stderr +++ b/tests/ui/const-generics/issues/issue-56445-1.min.stderr @@ -17,6 +17,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/issues/issue-56445-1.rs b/tests/ui/const-generics/issues/issue-56445-1.rs index 35126b3f55a..53aab40b0ad 100644 --- a/tests/ui/const-generics/issues/issue-56445-1.rs +++ b/tests/ui/const-generics/issues/issue-56445-1.rs @@ -1,6 +1,6 @@ // Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-518402995. //@ revisions: full min -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] #![crate_type = "lib"] diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr index 5082705927e..8ea96428deb 100644 --- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr +++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr @@ -4,7 +4,7 @@ error[E0741]: `&'static (dyn A + 'static)` can't be used as a const parameter ty LL | fn test<const T: &'static dyn A>() { | ^^^^^^^^^^^^^^ | - = note: `(dyn A + 'static)` must implement `ConstParamTy`, but it does not + = note: `(dyn A + 'static)` must implement `UnsizedConstParamTy`, but it does not error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr index 7f387cbd5a1..101ca456cd9 100644 --- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr +++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs index c5b83e9d529..9b15a8a7013 100644 --- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs +++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.rs @@ -1,5 +1,5 @@ //@ revisions: full min -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] trait A {} diff --git a/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs b/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs index 113bf94b5cb..41c5eaa0cd9 100644 --- a/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs +++ b/tests/ui/const-generics/issues/issue-66596-impl-trait-for-str-const-arg.rs @@ -1,8 +1,7 @@ //@ check-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] - trait Trait<const NAME: &'static str> { type Assoc; } diff --git a/tests/ui/const-generics/issues/issue-71547.rs b/tests/ui/const-generics/issues/issue-71547.rs index a2cea433a44..bb9ca63bd32 100644 --- a/tests/ui/const-generics/issues/issue-71547.rs +++ b/tests/ui/const-generics/issues/issue-71547.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub trait GetType<const N: &'static str> { diff --git a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr index e9363d42148..cba03b1cb1f 100644 --- a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr +++ b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.min.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs index 701b3423f31..fcab1f70507 100644 --- a/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs +++ b/tests/ui/const-generics/issues/issue-73727-static-reference-array-const-param.rs @@ -3,12 +3,12 @@ //@ revisions: full min //@[full]check-pass -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] fn a<const X: &'static [u32]>() {} //[min]~^ ERROR `&'static [u32]` is forbidden as the type of a const generic parameter fn main() { - a::<{&[]}>(); + a::<{ &[] }>(); } diff --git a/tests/ui/const-generics/issues/issue-86535-2.rs b/tests/ui/const-generics/issues/issue-86535-2.rs index bd9431dbc85..ab68c6b78df 100644 --- a/tests/ui/const-generics/issues/issue-86535-2.rs +++ b/tests/ui/const-generics/issues/issue-86535-2.rs @@ -1,10 +1,12 @@ //@ run-pass -#![feature(adt_const_params, generic_const_exprs)] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(incomplete_features)] pub trait Foo { const ASSOC_C: usize; - fn foo() where [(); Self::ASSOC_C]:; + fn foo() + where + [(); Self::ASSOC_C]:; } #[allow(dead_code)] @@ -12,7 +14,10 @@ struct Bar<const N: &'static ()>; impl<const N: &'static ()> Foo for Bar<N> { const ASSOC_C: usize = 3; - fn foo() where [u8; Self::ASSOC_C]: { + fn foo() + where + [u8; Self::ASSOC_C]:, + { let _: [u8; Self::ASSOC_C] = loop {}; } } diff --git a/tests/ui/const-generics/issues/issue-86535.rs b/tests/ui/const-generics/issues/issue-86535.rs index cd9934a4a99..9aaf7ddc9e8 100644 --- a/tests/ui/const-generics/issues/issue-86535.rs +++ b/tests/ui/const-generics/issues/issue-86535.rs @@ -1,5 +1,5 @@ //@ run-pass -#![feature(adt_const_params, generic_const_exprs)] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(incomplete_features, unused_variables)] #[allow(dead_code)] diff --git a/tests/ui/const-generics/issues/issue-90455.fixed b/tests/ui/const-generics/issues/issue-90455.fixed index 2502d47eb46..423a1fbd765 100644 --- a/tests/ui/const-generics/issues/issue-90455.fixed +++ b/tests/ui/const-generics/issues/issue-90455.fixed @@ -1,5 +1,5 @@ //@ run-rustfix -#![feature(generic_const_exprs, adt_const_params)] +#![feature(generic_const_exprs, unsized_const_params, adt_const_params)] #![allow(incomplete_features, dead_code)] struct FieldElement<const N: &'static str> where [(); num_limbs(N)]: { diff --git a/tests/ui/const-generics/issues/issue-90455.rs b/tests/ui/const-generics/issues/issue-90455.rs index 794c7d76cb1..be4f27ec689 100644 --- a/tests/ui/const-generics/issues/issue-90455.rs +++ b/tests/ui/const-generics/issues/issue-90455.rs @@ -1,5 +1,5 @@ //@ run-rustfix -#![feature(generic_const_exprs, adt_const_params)] +#![feature(generic_const_exprs, unsized_const_params, adt_const_params)] #![allow(incomplete_features, dead_code)] struct FieldElement<const N: &'static str> { diff --git a/tests/ui/const-generics/issues/issue-99641.stderr b/tests/ui/const-generics/issues/issue-99641.stderr index 800aec3ef2c..3365012a038 100644 --- a/tests/ui/const-generics/issues/issue-99641.stderr +++ b/tests/ui/const-generics/issues/issue-99641.stderr @@ -4,7 +4,7 @@ error[E0741]: `(fn(),)` can't be used as a const parameter type LL | pub struct Color<const WHITE: (fn(),)>; | ^^^^^^^ | - = note: `fn()` must implement `ConstParamTy`, but it does not + = note: `fn()` must implement `ConstParamTy_`, but it does not error[E0741]: `(fn(),)` can't be used as a const parameter type --> $DIR/issue-99641.rs:8:23 @@ -12,7 +12,7 @@ error[E0741]: `(fn(),)` can't be used as a const parameter type LL | impl<const WHITE: (fn(),)> Color<WHITE> { | ^^^^^^^ | - = note: `fn()` must implement `ConstParamTy`, but it does not + = note: `fn()` must implement `ConstParamTy_`, but it does not error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/min_const_generics/complex-types.stderr b/tests/ui/const-generics/min_const_generics/complex-types.stderr index 8e83ea58194..0211770f9e5 100644 --- a/tests/ui/const-generics/min_const_generics/complex-types.stderr +++ b/tests/ui/const-generics/min_const_generics/complex-types.stderr @@ -45,6 +45,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `!` is forbidden as the type of a const generic parameter --> $DIR/complex-types.rs:17:21 diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr new file mode 100644 index 00000000000..18f47f7dc23 --- /dev/null +++ b/tests/ui/const-generics/raw-ptr-const-param-deref.adt_const_params.stderr @@ -0,0 +1,15 @@ +error[E0741]: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param-deref.rs:11:23 + | +LL | struct Const<const P: *const u32>; + | ^^^^^^^^^^ + +error[E0741]: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param-deref.rs:13:15 + | +LL | impl<const P: *const u32> Const<P> { + | ^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr index 657eee2be24..18f47f7dc23 100644 --- a/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr +++ b/tests/ui/const-generics/raw-ptr-const-param-deref.full.stderr @@ -1,11 +1,11 @@ error[E0741]: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param-deref.rs:9:23 + --> $DIR/raw-ptr-const-param-deref.rs:11:23 | LL | struct Const<const P: *const u32>; | ^^^^^^^^^^ error[E0741]: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param-deref.rs:11:15 + --> $DIR/raw-ptr-const-param-deref.rs:13:15 | LL | impl<const P: *const u32> Const<P> { | ^^^^^^^^^^ diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr index 1eb238255ab..6027dbb01cd 100644 --- a/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr +++ b/tests/ui/const-generics/raw-ptr-const-param-deref.min.stderr @@ -1,5 +1,5 @@ error: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param-deref.rs:9:23 + --> $DIR/raw-ptr-const-param-deref.rs:11:23 | LL | struct Const<const P: *const u32>; | ^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | struct Const<const P: *const u32>; = note: the only supported types are integers, `bool` and `char` error: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param-deref.rs:11:15 + --> $DIR/raw-ptr-const-param-deref.rs:13:15 | LL | impl<const P: *const u32> Const<P> { | ^^^^^^^^^^ diff --git a/tests/ui/const-generics/raw-ptr-const-param-deref.rs b/tests/ui/const-generics/raw-ptr-const-param-deref.rs index b7fcbb3447a..bf077acd4fa 100644 --- a/tests/ui/const-generics/raw-ptr-const-param-deref.rs +++ b/tests/ui/const-generics/raw-ptr-const-param-deref.rs @@ -1,21 +1,22 @@ // Checks that pointers must not be used as the type of const params. -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] const A: u32 = 3; struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters -impl<const P: *const u32> Const<P> { //~ ERROR: using raw pointers as const generic parameters +impl<const P: *const u32> Const<P> { + //~^ ERROR: using raw pointers as const generic parameters fn get() -> u32 { - unsafe { - *P - } + unsafe { *P } } } fn main() { - assert_eq!(Const::<{&A as *const _}>::get(), 3) + assert_eq!(Const::<{ &A as *const _ }>::get(), 3) } diff --git a/tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr b/tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr new file mode 100644 index 00000000000..f040d3cc36a --- /dev/null +++ b/tests/ui/const-generics/raw-ptr-const-param.adt_const_params.stderr @@ -0,0 +1,21 @@ +error[E0741]: using raw pointers as const generic parameters is forbidden + --> $DIR/raw-ptr-const-param.rs:8:23 + | +LL | struct Const<const P: *const u32>; + | ^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/raw-ptr-const-param.rs:11:40 + | +LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; + | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` + | | + | expected due to this + | + = note: expected struct `Const<{0xf as *const u32}>` + found struct `Const<{0xa as *const u32}>` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0308, E0741. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/raw-ptr-const-param.full.stderr b/tests/ui/const-generics/raw-ptr-const-param.full.stderr index 7ba9ac15bf3..f040d3cc36a 100644 --- a/tests/ui/const-generics/raw-ptr-const-param.full.stderr +++ b/tests/ui/const-generics/raw-ptr-const-param.full.stderr @@ -1,11 +1,11 @@ error[E0741]: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param.rs:6:23 + --> $DIR/raw-ptr-const-param.rs:8:23 | LL | struct Const<const P: *const u32>; | ^^^^^^^^^^ error[E0308]: mismatched types - --> $DIR/raw-ptr-const-param.rs:9:40 + --> $DIR/raw-ptr-const-param.rs:11:40 | LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` diff --git a/tests/ui/const-generics/raw-ptr-const-param.min.stderr b/tests/ui/const-generics/raw-ptr-const-param.min.stderr index 18bbcc33c4d..c48eea069e0 100644 --- a/tests/ui/const-generics/raw-ptr-const-param.min.stderr +++ b/tests/ui/const-generics/raw-ptr-const-param.min.stderr @@ -1,5 +1,5 @@ error: using raw pointers as const generic parameters is forbidden - --> $DIR/raw-ptr-const-param.rs:6:23 + --> $DIR/raw-ptr-const-param.rs:8:23 | LL | struct Const<const P: *const u32>; | ^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | struct Const<const P: *const u32>; = note: the only supported types are integers, `bool` and `char` error[E0308]: mismatched types - --> $DIR/raw-ptr-const-param.rs:9:40 + --> $DIR/raw-ptr-const-param.rs:11:40 | LL | let _: Const<{ 15 as *const _ }> = Const::<{ 10 as *const _ }>; | ------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `{0xf as *const u32}`, found `{0xa as *const u32}` diff --git a/tests/ui/const-generics/raw-ptr-const-param.rs b/tests/ui/const-generics/raw-ptr-const-param.rs index 19d18a2f9d2..49e48d9905f 100644 --- a/tests/ui/const-generics/raw-ptr-const-param.rs +++ b/tests/ui/const-generics/raw-ptr-const-param.rs @@ -1,7 +1,9 @@ -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] struct Const<const P: *const u32>; //~ ERROR: using raw pointers as const generic parameters diff --git a/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr b/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr new file mode 100644 index 00000000000..bcb2bd255da --- /dev/null +++ b/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr @@ -0,0 +1,49 @@ +error[E0741]: `&'static str` can't be used as a const parameter type + --> $DIR/slice-const-param-mismatch.rs:8:29 + | +LL | struct ConstString<const T: &'static str>; + | ^^^^^^^^^^^^ + +error[E0741]: `&'static [u8]` can't be used as a const parameter type + --> $DIR/slice-const-param-mismatch.rs:11:28 + | +LL | struct ConstBytes<const T: &'static [u8]>; + | ^^^^^^^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:17:35 + | +LL | let _: ConstString<"Hello"> = ConstString::<"World">; + | -------------------- ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"` + | | + | expected due to this + | + = note: expected struct `ConstString<"Hello">` + found struct `ConstString<"World">` + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:19:33 + | +LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; + | ------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"` + | | + | expected due to this + | + = note: expected struct `ConstString<"ℇ㇈↦">` + found struct `ConstString<"ℇ㇈↥">` + +error[E0308]: mismatched types + --> $DIR/slice-const-param-mismatch.rs:21:33 + | +LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; + | ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"` + | | + | expected due to this + | + = note: expected struct `ConstBytes<b"AAA">` + found struct `ConstBytes<b"BBB">` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0308, E0741. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/slice-const-param-mismatch.full.stderr b/tests/ui/const-generics/slice-const-param-mismatch.full.stderr index 80dd1be33c2..883ba988be7 100644 --- a/tests/ui/const-generics/slice-const-param-mismatch.full.stderr +++ b/tests/ui/const-generics/slice-const-param-mismatch.full.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:14:35 + --> $DIR/slice-const-param-mismatch.rs:17:35 | LL | let _: ConstString<"Hello"> = ConstString::<"World">; | -------------------- ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"` @@ -10,7 +10,7 @@ LL | let _: ConstString<"Hello"> = ConstString::<"World">; found struct `ConstString<"World">` error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:16:33 + --> $DIR/slice-const-param-mismatch.rs:19:33 | LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; | ------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"` @@ -21,7 +21,7 @@ LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; found struct `ConstString<"ℇ㇈↥">` error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:18:33 + --> $DIR/slice-const-param-mismatch.rs:21:33 | LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; | ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"` diff --git a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr index 0650dafc685..3b2410c9894 100644 --- a/tests/ui/const-generics/slice-const-param-mismatch.min.stderr +++ b/tests/ui/const-generics/slice-const-param-mismatch.min.stderr @@ -1,5 +1,5 @@ error: `&'static str` is forbidden as the type of a const generic parameter - --> $DIR/slice-const-param-mismatch.rs:7:29 + --> $DIR/slice-const-param-mismatch.rs:8:29 | LL | struct ConstString<const T: &'static str>; | ^^^^^^^^^^^^ @@ -9,9 +9,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&'static [u8]` is forbidden as the type of a const generic parameter - --> $DIR/slice-const-param-mismatch.rs:9:28 + --> $DIR/slice-const-param-mismatch.rs:11:28 | LL | struct ConstBytes<const T: &'static [u8]>; | ^^^^^^^^^^^^^ @@ -21,9 +25,13 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:14:35 + --> $DIR/slice-const-param-mismatch.rs:17:35 | LL | let _: ConstString<"Hello"> = ConstString::<"World">; | -------------------- ^^^^^^^^^^^^^^^^^^^^^^ expected `"Hello"`, found `"World"` @@ -34,7 +42,7 @@ LL | let _: ConstString<"Hello"> = ConstString::<"World">; found struct `ConstString<"World">` error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:16:33 + --> $DIR/slice-const-param-mismatch.rs:19:33 | LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; | ------------------- ^^^^^^^^^^^^^^^^^^^^^ expected `"ℇ㇈↦"`, found `"ℇ㇈↥"` @@ -45,7 +53,7 @@ LL | let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; found struct `ConstString<"ℇ㇈↥">` error[E0308]: mismatched types - --> $DIR/slice-const-param-mismatch.rs:18:33 + --> $DIR/slice-const-param-mismatch.rs:21:33 | LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; | ------------------ ^^^^^^^^^^^^^^^^^^^^ expected `b"AAA"`, found `b"BBB"` diff --git a/tests/ui/const-generics/slice-const-param-mismatch.rs b/tests/ui/const-generics/slice-const-param-mismatch.rs index 733eeb69fa9..feee39e602d 100644 --- a/tests/ui/const-generics/slice-const-param-mismatch.rs +++ b/tests/ui/const-generics/slice-const-param-mismatch.rs @@ -1,19 +1,22 @@ -//@ revisions: full min +//@ revisions: min adt_const_params full -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] - +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] struct ConstString<const T: &'static str>; //[min]~^ ERROR +//[adt_const_params]~^^ ERROR struct ConstBytes<const T: &'static [u8]>; //[min]~^ ERROR +//[adt_const_params]~^^ ERROR pub fn main() { let _: ConstString<"Hello"> = ConstString::<"Hello">; let _: ConstString<"Hello"> = ConstString::<"World">; //~ ERROR mismatched types let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↦">; let _: ConstString<"ℇ㇈↦"> = ConstString::<"ℇ㇈↥">; //~ ERROR mismatched types - let _: ConstBytes<b"AAA"> = ConstBytes::<{&[0x41, 0x41, 0x41]}>; + let _: ConstBytes<b"AAA"> = ConstBytes::<{ &[0x41, 0x41, 0x41] }>; let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; //~ ERROR mismatched types } diff --git a/tests/ui/const-generics/slice-const-param.rs b/tests/ui/const-generics/slice-const-param.rs index c6c0047c929..1c5088b5283 100644 --- a/tests/ui/const-generics/slice-const-param.rs +++ b/tests/ui/const-generics/slice-const-param.rs @@ -1,6 +1,6 @@ //@ run-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] pub fn function_with_str<const STRING: &'static str>() -> &'static str { @@ -12,9 +12,8 @@ pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] { } // Also check the codepaths for custom DST -#[derive(PartialEq, Eq)] +#[derive(std::marker::UnsizedConstParamTy, PartialEq, Eq)] struct MyStr(str); -impl std::marker::ConstParamTy for MyStr {} fn function_with_my_str<const S: &'static MyStr>() -> &'static MyStr { S @@ -34,7 +33,7 @@ pub fn main() { assert_eq!(function_with_str::<"Rust">(), "Rust"); assert_eq!(function_with_str::<"ℇ㇈↦">(), "ℇ㇈↦"); assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]); - assert_eq!(function_with_bytes::<{&[0x41, 0x41, 0x41, 0x41]}>(), b"AAAA"); + assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA"); assert_eq!(function_with_my_str::<{ MyStr::new("hello") }>().as_str(), "hello"); } diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr new file mode 100644 index 00000000000..7a936ced030 --- /dev/null +++ b/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr @@ -0,0 +1,9 @@ +error[E0741]: `&'static ()` can't be used as a const parameter type + --> $DIR/transmute-const-param-static-reference.rs:9:23 + | +LL | struct Const<const P: &'static ()>; + | ^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr index fdb6ddeb578..cf236487cf0 100644 --- a/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr +++ b/tests/ui/const-generics/transmute-const-param-static-reference.min.stderr @@ -1,5 +1,5 @@ error: `&'static ()` is forbidden as the type of a const generic parameter - --> $DIR/transmute-const-param-static-reference.rs:7:23 + --> $DIR/transmute-const-param-static-reference.rs:9:23 | LL | struct Const<const P: &'static ()>; | ^^^^^^^^^^^ @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.rs b/tests/ui/const-generics/transmute-const-param-static-reference.rs index 49541233ed1..0b47fd31eaf 100644 --- a/tests/ui/const-generics/transmute-const-param-static-reference.rs +++ b/tests/ui/const-generics/transmute-const-param-static-reference.rs @@ -1,16 +1,17 @@ -//@ revisions: full min +//@ revisions: full adt_const_params min //@[full] check-pass -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(adt_const_params, feature(adt_const_params))] +#![cfg_attr(adt_const_params, allow(incomplete_features))] struct Const<const P: &'static ()>; //[min]~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter +//[adt_const_params]~^^ ERROR `&'static ()` can't be used as a const parameter type fn main() { - const A: &'static () = unsafe { - std::mem::transmute(10 as *const ()) - }; + const A: &'static () = unsafe { std::mem::transmute(10 as *const ()) }; - let _ = Const::<{A}>; + let _ = Const::<{ A }>; } diff --git a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr index f42a331a8a4..858900a500d 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.min.stderr +++ b/tests/ui/const-generics/type-dependent/issue-71348.min.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/issue-71348.rs:18:25 @@ -21,6 +25,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/type-dependent/issue-71348.rs b/tests/ui/const-generics/type-dependent/issue-71348.rs index f349a88d124..2ffbd015485 100644 --- a/tests/ui/const-generics/type-dependent/issue-71348.rs +++ b/tests/ui/const-generics/type-dependent/issue-71348.rs @@ -1,6 +1,6 @@ //@ [full] run-pass //@ revisions: full min -#![cfg_attr(full, feature(adt_const_params))] +#![cfg_attr(full, feature(adt_const_params, unsized_const_params))] #![cfg_attr(full, allow(incomplete_features))] struct Foo { diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.rs b/tests/ui/consts/refs_check_const_eq-issue-88384.rs index fb0405b651c..46cb6275171 100644 --- a/tests/ui/consts/refs_check_const_eq-issue-88384.rs +++ b/tests/ui/consts/refs_check_const_eq-issue-88384.rs @@ -1,10 +1,10 @@ #![feature(fn_traits)] -#![feature(adt_const_params)] -//~^ WARNING the feature `adt_const_params` is incomplete +#![feature(adt_const_params, unsized_const_params)] +//~^ WARNING the feature `unsized_const_params` is incomplete #[derive(PartialEq, Eq)] -struct CompileTimeSettings{ - hooks: &'static[fn()], +struct CompileTimeSettings { + hooks: &'static [fn()], } struct Foo<const T: CompileTimeSettings>; @@ -12,14 +12,11 @@ struct Foo<const T: CompileTimeSettings>; impl<const T: CompileTimeSettings> Foo<T> { //~^ ERROR `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter - fn call_hooks(){ - } + fn call_hooks() {} } -fn main(){ - const SETTINGS: CompileTimeSettings = CompileTimeSettings{ - hooks: &[], - }; +fn main() { + const SETTINGS: CompileTimeSettings = CompileTimeSettings { hooks: &[] }; Foo::<SETTINGS>::call_hooks(); } diff --git a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr index c490cd053e7..62c5c527641 100644 --- a/tests/ui/consts/refs_check_const_eq-issue-88384.stderr +++ b/tests/ui/consts/refs_check_const_eq-issue-88384.stderr @@ -1,8 +1,8 @@ -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/refs_check_const_eq-issue-88384.rs:2:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/refs_check_const_eq-issue-88384.rs:2:30 | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information = note: `#[warn(incomplete_features)]` on by default @@ -16,7 +16,7 @@ LL | struct Foo<const T: CompileTimeSettings>; help: add `#[derive(ConstParamTy)]` to the struct | LL + #[derive(ConstParamTy)] -LL | struct CompileTimeSettings{ +LL | struct CompileTimeSettings { | error[E0741]: `CompileTimeSettings` must implement `ConstParamTy` to be used as the type of a const generic parameter @@ -28,7 +28,7 @@ LL | impl<const T: CompileTimeSettings> Foo<T> { help: add `#[derive(ConstParamTy)]` to the struct | LL + #[derive(ConstParamTy)] -LL | struct CompileTimeSettings{ +LL | struct CompileTimeSettings { | error: aborting due to 2 previous errors; 1 warning emitted diff --git a/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs b/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs index 446fdc75514..33b6b7f52ca 100644 --- a/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs +++ b/tests/ui/consts/refs_check_const_value_eq-issue-88876.rs @@ -1,7 +1,7 @@ //@ check-pass #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] struct FooConst<const ARRAY: &'static [&'static str]> {} diff --git a/tests/ui/error-codes/E0771.rs b/tests/ui/error-codes/E0771.rs index c0a2e98a7df..a932c5ef981 100644 --- a/tests/ui/error-codes/E0771.rs +++ b/tests/ui/error-codes/E0771.rs @@ -1,5 +1,5 @@ -#![feature(adt_const_params)] -//~^ WARN the feature `adt_const_params` is incomplete +#![feature(adt_const_params, unsized_const_params)] +//~^ WARN the feature `unsized_const_params` is incomplete fn function_with_str<'a, const STRING: &'a str>() {} //~ ERROR E0770 diff --git a/tests/ui/error-codes/E0771.stderr b/tests/ui/error-codes/E0771.stderr index e1384effe37..5e829e6f6d2 100644 --- a/tests/ui/error-codes/E0771.stderr +++ b/tests/ui/error-codes/E0771.stderr @@ -6,11 +6,11 @@ LL | fn function_with_str<'a, const STRING: &'a str>() {} | = note: lifetime parameters may not be used in the type of const parameters -warning: the feature `adt_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/E0771.rs:1:12 +warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/E0771.rs:1:30 | -LL | #![feature(adt_const_params)] - | ^^^^^^^^^^^^^^^^ +LL | #![feature(adt_const_params, unsized_const_params)] + | ^^^^^^^^^^^^^^^^^^^^ | = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information = note: `#[warn(incomplete_features)]` on by default diff --git a/tests/ui/errors/wrong-target-spec.rs b/tests/ui/errors/wrong-target-spec.rs new file mode 100644 index 00000000000..bc9038c1fab --- /dev/null +++ b/tests/ui/errors/wrong-target-spec.rs @@ -0,0 +1,8 @@ +// The attentive may note the underscores in the target triple, making it invalid. This test +// checks that such invalid target specs are rejected by the compiler. +// See https://github.com/rust-lang/rust/issues/33329 + +//@ needs-llvm-components: x86 +//@ compile-flags: --target x86_64_unknown-linux-musl + +fn main() {} diff --git a/tests/ui/errors/wrong-target-spec.stderr b/tests/ui/errors/wrong-target-spec.stderr new file mode 100644 index 00000000000..8b06f404078 --- /dev/null +++ b/tests/ui/errors/wrong-target-spec.stderr @@ -0,0 +1,2 @@ +error: Error loading target specification: Could not find specification for target "x86_64_unknown-linux-musl". Run `rustc --print target-list` for a list of built-in targets + diff --git a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr index fcb9b8a6fc5..649e936888b 100644 --- a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr +++ b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 1 previous error diff --git a/tests/ui/feature-gates/feature-gate-unsized-const-params.rs b/tests/ui/feature-gates/feature-gate-unsized-const-params.rs new file mode 100644 index 00000000000..d088d382377 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsized-const-params.rs @@ -0,0 +1,6 @@ +struct Foo<const N: [u8]>; +//~^ ERROR: `[u8]` is forbidden as the type of a const generic parameter +//~| HELP: add `#![feature(adt_const_params)]` to the crate +//~| HELP: add `#![feature(unsized_const_params)]` to the crate + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr new file mode 100644 index 00000000000..0a87f34f4f5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-unsized-const-params.stderr @@ -0,0 +1,18 @@ +error: `[u8]` is forbidden as the type of a const generic parameter + --> $DIR/feature-gate-unsized-const-params.rs:1:21 + | +LL | struct Foo<const N: [u8]>; + | ^^^^ + | + = note: the only supported types are integers, `bool` and `char` +help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types + | +LL + #![feature(adt_const_params)] + | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | + +error: aborting due to 1 previous error + 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 4205c5c5ef7..d1decc0c3f1 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 @@ -13,8 +13,8 @@ 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: - Fooer<T> Fooy + Fooer<T> error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/gat-in-trait-path.rs:32:5 @@ -31,8 +31,8 @@ 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: - Fooer<T> Fooy + Fooer<T> error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/gat-in-trait-path.rs:32:5 @@ -49,8 +49,8 @@ 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: - Fooer<T> Fooy + Fooer<T> = note: required for the cast from `Box<Fooer<{integer}>>` to `Box<(dyn Foo<A = &'a ()> + 'static)>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/issue-79422.base.stderr b/tests/ui/generic-associated-types/issue-79422.base.stderr index 7f58f825702..bcc6382cf7c 100644 --- a/tests/ui/generic-associated-types/issue-79422.base.stderr +++ b/tests/ui/generic-associated-types/issue-79422.base.stderr @@ -29,8 +29,8 @@ 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: - Source std::collections::BTreeMap<K, V> + Source error[E0038]: the trait `MapLike` cannot be made into an object --> $DIR/issue-79422.rs:44:13 @@ -47,8 +47,8 @@ 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: - Source 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-const-items/elided-lifetimes.stderr b/tests/ui/generic-const-items/elided-lifetimes.stderr index 1d4a997ff60..85807a1b631 100644 --- a/tests/ui/generic-const-items/elided-lifetimes.stderr +++ b/tests/ui/generic-const-items/elided-lifetimes.stderr @@ -32,6 +32,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs index a6dcad3face..00034fb9f44 100644 --- a/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs +++ b/tests/ui/impl-trait/defining-use-uncaptured-non-universal-region-3.rs @@ -1,6 +1,6 @@ //@ check-pass -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] trait Bar<const FOO: &'static str> {} diff --git a/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs index b6395258c89..9205f1e1632 100644 --- a/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs +++ b/tests/ui/impl-trait/static-lifetime-return-position-impl-trait.rs @@ -1,7 +1,7 @@ //@ check-pass #![allow(incomplete_features)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] pub struct Element; diff --git a/tests/ui/inference/ice-cannot-relate-region-109178.rs b/tests/ui/inference/ice-cannot-relate-region-109178.rs index 3282f95a992..2e3953646ff 100644 --- a/tests/ui/inference/ice-cannot-relate-region-109178.rs +++ b/tests/ui/inference/ice-cannot-relate-region-109178.rs @@ -2,7 +2,7 @@ #![allow(incomplete_features)] #![crate_type = "lib"] -#![feature(adt_const_params, generic_const_exprs)] +#![feature(adt_const_params, unsized_const_params, generic_const_exprs)] struct Changes<const CHANGES: &[&'static str]> //~^ ERROR `&` without an explicit lifetime name cannot be used here diff --git a/tests/ui/lifetimes/unusual-rib-combinations.stderr b/tests/ui/lifetimes/unusual-rib-combinations.stderr index 70f06b4be60..e446345aedc 100644 --- a/tests/ui/lifetimes/unusual-rib-combinations.stderr +++ b/tests/ui/lifetimes/unusual-rib-combinations.stderr @@ -63,6 +63,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: aborting due to 8 previous errors diff --git a/tests/ui/lto/debuginfo-lto-alloc.rs b/tests/ui/lto/debuginfo-lto-alloc.rs index 459103c354c..89043275329 100644 --- a/tests/ui/lto/debuginfo-lto-alloc.rs +++ b/tests/ui/lto/debuginfo-lto-alloc.rs @@ -9,7 +9,8 @@ // that compilation is successful. //@ check-pass -//@ compile-flags: --test -C debuginfo=2 -C lto=fat -C incremental=inc-fat +//@ compile-flags: --test -C debuginfo=2 -C lto=fat +//@ incremental extern crate alloc; diff --git a/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs b/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs new file mode 100644 index 00000000000..781443207ac --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs @@ -0,0 +1,18 @@ +//@ run-pass + +#![feature(macro_metavar_expr_concat)] + +macro_rules! one_rep { + ( $($a:ident)* ) => { + $( + const ${concat($a, Z)}: i32 = 3; + )* + }; +} + +fn main() { + one_rep!(A B C); + assert_eq!(AZ, 3); + assert_eq!(BZ, 3); + assert_eq!(CZ, 3); +} diff --git a/tests/ui/mir/ice-mir-const-qualif-125837.rs b/tests/ui/mir/ice-mir-const-qualif-125837.rs new file mode 100644 index 00000000000..a0f57caaba4 --- /dev/null +++ b/tests/ui/mir/ice-mir-const-qualif-125837.rs @@ -0,0 +1,17 @@ +// Test for ICE: mir_const_qualif: index out of bounds: the len is 0 but the index is 0 +// https://github.com/rust-lang/rust/issues/125837 + +use std::fmt::Debug; + +trait Foo<Item> {} + +impl<Item, D: Debug + Clone> Foo for D { +//~^ ERROR missing generics for trait `Foo` + fn foo<'a>(&'a self) -> impl Debug { + //~^ ERROR method `foo` is not a member of trait `Foo` + const { return } +//~^ ERROR return statement outside of function body + } +} + +pub fn main() {} diff --git a/tests/ui/mir/ice-mir-const-qualif-125837.stderr b/tests/ui/mir/ice-mir-const-qualif-125837.stderr new file mode 100644 index 00000000000..003b327210b --- /dev/null +++ b/tests/ui/mir/ice-mir-const-qualif-125837.stderr @@ -0,0 +1,41 @@ +error[E0407]: method `foo` is not a member of trait `Foo` + --> $DIR/ice-mir-const-qualif-125837.rs:10:5 + | +LL | / fn foo<'a>(&'a self) -> impl Debug { +LL | | +LL | | const { return } +LL | | +LL | | } + | |_____^ not a member of trait `Foo` + +error[E0107]: missing generics for trait `Foo` + --> $DIR/ice-mir-const-qualif-125837.rs:8:30 + | +LL | impl<Item, D: Debug + Clone> Foo for D { + | ^^^ expected 1 generic argument + | +note: trait defined here, with 1 generic parameter: `Item` + --> $DIR/ice-mir-const-qualif-125837.rs:6:7 + | +LL | trait Foo<Item> {} + | ^^^ ---- +help: add missing generic argument + | +LL | impl<Item, D: Debug + Clone> Foo<Item> for D { + | ++++++ + +error[E0572]: return statement outside of function body + --> $DIR/ice-mir-const-qualif-125837.rs:12:17 + | +LL | / fn foo<'a>(&'a self) -> impl Debug { +LL | | +LL | | const { return } + | | --^^^^^^-- the return is part of this body... +LL | | +LL | | } + | |_____- ...not the enclosing function body + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0107, E0407, E0572. +For more information about an error, try `rustc --explain E0107`. diff --git a/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr index 6e50dfe6a26..9b57c895eea 100644 --- a/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr +++ b/tests/ui/pattern/usefulness/empty-types.min_exh_pats.stderr @@ -204,6 +204,7 @@ note: `Option<Void>` defined here | = note: not covered = note: the matched value is of type `Option<Void>` + = note: `Void` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => {}, @@ -349,6 +350,7 @@ LL | match slice_never { | ^^^^^^^^^^^ pattern `&[_, ..]` not covered | = note: the matched value is of type `&[!]` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ [] => {}, @@ -484,6 +486,7 @@ note: `Option<!>` defined here | = note: not covered = note: the matched value is of type `&Option<!>` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ &None => {}, @@ -502,6 +505,7 @@ note: `Option<!>` defined here | = note: not covered = note: the matched value is of type `Option<!>` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => {}, @@ -520,6 +524,7 @@ note: `Result<!, !>` defined here | = note: not covered = note: the matched value is of type `Result<!, !>` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Ok(_) => {}, @@ -538,6 +543,7 @@ note: `Result<!, !>` defined here | = note: not covered = note: the matched value is of type `Result<!, !>` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Ok(_a) => {}, @@ -589,6 +595,7 @@ LL | match ref_never { | ^^^^^^^^^ pattern `&_` not covered | = note: the matched value is of type `&!` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required = note: references are always considered inhabited = note: match arms with guards don't count towards exhaustivity help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown @@ -609,6 +616,7 @@ note: `Result<!, !>` defined here | = note: not covered = note: the matched value is of type `Result<!, !>` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ Err(_) => {}, @@ -627,6 +635,7 @@ note: `Option<Result<!, !>>` defined here | = note: not covered = note: the matched value is of type `Option<Result<!, !>>` + = note: `Result<!, !>` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ None => {}, diff --git a/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr b/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr index a1239466c9c..f24ce154d14 100644 --- a/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr +++ b/tests/ui/pattern/usefulness/slice_of_empty.min_exhaustive_patterns.stderr @@ -5,6 +5,7 @@ LL | match nevers { | ^^^^^^ pattern `&[_, ..]` not covered | = note: the matched value is of type `&[!]` + = note: `!` is uninhabited but is not being matched by value, so a wildcard `_` is required help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ &[] => (), diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.fixed b/tests/ui/rust-2024/unsafe-env-suggestion.fixed index 1f3d2dc0a31..eba35180ef6 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.fixed +++ b/tests/ui/rust-2024/unsafe-env-suggestion.fixed @@ -1,6 +1,6 @@ //@ run-rustfix -#![deny(deprecated_safe)] +#![deny(deprecated_safe_2024)] use std::env; diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.rs b/tests/ui/rust-2024/unsafe-env-suggestion.rs index 3bd169973e3..c039d7f2583 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.rs +++ b/tests/ui/rust-2024/unsafe-env-suggestion.rs @@ -1,6 +1,6 @@ //@ run-rustfix -#![deny(deprecated_safe)] +#![deny(deprecated_safe_2024)] use std::env; diff --git a/tests/ui/rust-2024/unsafe-env-suggestion.stderr b/tests/ui/rust-2024/unsafe-env-suggestion.stderr index 7c12f4aa5ed..3aa10a3bed6 100644 --- a/tests/ui/rust-2024/unsafe-env-suggestion.stderr +++ b/tests/ui/rust-2024/unsafe-env-suggestion.stderr @@ -9,8 +9,8 @@ LL | env::set_var("FOO", "BAR"); note: the lint level is defined here --> $DIR/unsafe-env-suggestion.rs:3:9 | -LL | #![deny(deprecated_safe)] - | ^^^^^^^^^^^^^^^ +LL | #![deny(deprecated_safe_2024)] + | ^^^^^^^^^^^^^^^^^^^^ help: you can wrap the call in an `unsafe` block if you can guarantee the code is only ever called from single-threaded code | LL + // TODO: Audit that the environment access only happens in single-threaded code. diff --git a/tests/ui/simd/intrinsic/generic-elements.rs b/tests/ui/simd/intrinsic/generic-elements.rs index abceb08ecc5..aec75a67306 100644 --- a/tests/ui/simd/intrinsic/generic-elements.rs +++ b/tests/ui/simd/intrinsic/generic-elements.rs @@ -1,6 +1,6 @@ //@ build-fail -#![feature(repr_simd, intrinsics, rustc_attrs, adt_const_params)] +#![feature(repr_simd, intrinsics, rustc_attrs, adt_const_params, unsized_const_params)] #![allow(incomplete_features)] #[repr(simd)] @@ -14,8 +14,7 @@ struct i32x4(i32, i32, i32, i32); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, - i32, i32, i32, i32); +struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); #[repr(simd)] #[derive(Copy, Clone)] @@ -28,8 +27,7 @@ struct f32x4(f32, f32, f32, f32); #[repr(simd)] #[derive(Copy, Clone)] #[allow(non_camel_case_types)] -struct f32x8(f32, f32, f32, f32, - f32, f32, f32, f32); +struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); extern "rust-intrinsic" { fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T; @@ -61,11 +59,11 @@ fn main() { //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shuffle::<_, _, f32x2>(x, x, IDX2); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` simd_shuffle::<_, _, f32x4>(x, x, IDX4); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` simd_shuffle::<_, _, f32x8>(x, x, IDX8); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` simd_shuffle::<_, _, i32x8>(x, x, IDX2); //~^ ERROR expected return type of length 2, found `i32x8` with length 8 @@ -85,11 +83,11 @@ fn main() { //~^ ERROR expected SIMD input type, found non-SIMD `i32` simd_shuffle_generic::<_, f32x2, I2>(x, x); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` simd_shuffle_generic::<_, f32x4, I4>(x, x); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` simd_shuffle_generic::<_, f32x8, I8>(x, x); -//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` + //~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` simd_shuffle_generic::<_, i32x8, I2>(x, x); //~^ ERROR expected return type of length 2, found `i32x8` with length 8 diff --git a/tests/ui/simd/intrinsic/generic-elements.stderr b/tests/ui/simd/intrinsic/generic-elements.stderr index 26e01344939..0788a7c17f9 100644 --- a/tests/ui/simd/intrinsic/generic-elements.stderr +++ b/tests/ui/simd/intrinsic/generic-elements.stderr @@ -1,125 +1,125 @@ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:46:9 + --> $DIR/generic-elements.rs:44:9 | LL | simd_insert(0, 0, 0); | ^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64` - --> $DIR/generic-elements.rs:48:9 + --> $DIR/generic-elements.rs:46:9 | LL | simd_insert(x, 0, 1.0); | ^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32` - --> $DIR/generic-elements.rs:50:9 + --> $DIR/generic-elements.rs:48:9 | LL | simd_extract::<_, f32>(x, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:54:9 + --> $DIR/generic-elements.rs:52:9 | LL | simd_shuffle::<i32, _, i32>(0, 0, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:57:9 + --> $DIR/generic-elements.rs:55:9 | LL | simd_shuffle::<i32, _, i32>(0, 0, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:60:9 + --> $DIR/generic-elements.rs:58:9 | LL | simd_shuffle::<i32, _, i32>(0, 0, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - --> $DIR/generic-elements.rs:63:9 + --> $DIR/generic-elements.rs:61:9 | LL | simd_shuffle::<_, _, f32x2>(x, x, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - --> $DIR/generic-elements.rs:65:9 + --> $DIR/generic-elements.rs:63:9 | LL | simd_shuffle::<_, _, f32x4>(x, x, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/generic-elements.rs:67:9 + --> $DIR/generic-elements.rs:65:9 | LL | simd_shuffle::<_, _, f32x8>(x, x, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:70:9 + --> $DIR/generic-elements.rs:68:9 | LL | simd_shuffle::<_, _, i32x8>(x, x, IDX2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 4, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:72:9 + --> $DIR/generic-elements.rs:70:9 | LL | simd_shuffle::<_, _, i32x8>(x, x, IDX4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/generic-elements.rs:74:9 + --> $DIR/generic-elements.rs:72:9 | LL | simd_shuffle::<_, _, i32x2>(x, x, IDX8); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:78:9 + --> $DIR/generic-elements.rs:76:9 | LL | simd_shuffle_generic::<i32, i32, I2>(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:81:9 + --> $DIR/generic-elements.rs:79:9 | LL | simd_shuffle_generic::<i32, i32, I4>(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected SIMD input type, found non-SIMD `i32` - --> $DIR/generic-elements.rs:84:9 + --> $DIR/generic-elements.rs:82:9 | LL | simd_shuffle_generic::<i32, i32, I8>(0, 0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` - --> $DIR/generic-elements.rs:87:9 + --> $DIR/generic-elements.rs:85:9 | LL | simd_shuffle_generic::<_, f32x2, I2>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` - --> $DIR/generic-elements.rs:89:9 + --> $DIR/generic-elements.rs:87:9 | LL | simd_shuffle_generic::<_, f32x4, I4>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` - --> $DIR/generic-elements.rs:91:9 + --> $DIR/generic-elements.rs:89:9 | LL | simd_shuffle_generic::<_, f32x8, I8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 2, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:94:9 + --> $DIR/generic-elements.rs:92:9 | LL | simd_shuffle_generic::<_, i32x8, I2>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 4, found `i32x8` with length 8 - --> $DIR/generic-elements.rs:96:9 + --> $DIR/generic-elements.rs:94:9 | LL | simd_shuffle_generic::<_, i32x8, I4>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0511]: invalid monomorphization of `simd_shuffle_generic` intrinsic: expected return type of length 8, found `i32x2` with length 2 - --> $DIR/generic-elements.rs:98:9 + --> $DIR/generic-elements.rs:96:9 | LL | simd_shuffle_generic::<_, i32x2, I8>(x, x); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/simd/monomorphize-shuffle-index.rs b/tests/ui/simd/monomorphize-shuffle-index.rs index 379616884a1..30c345cb904 100644 --- a/tests/ui/simd/monomorphize-shuffle-index.rs +++ b/tests/ui/simd/monomorphize-shuffle-index.rs @@ -1,7 +1,7 @@ //@[old]run-pass //@[generic_with_fn]run-pass //@ revisions: old generic generic_with_fn -#![feature(repr_simd, intrinsics, adt_const_params, generic_const_exprs)] +#![feature(repr_simd, intrinsics, adt_const_params, unsized_const_params, generic_const_exprs)] #![allow(incomplete_features)] extern "rust-intrinsic" { diff --git a/tests/ui/statics/const_generics.rs b/tests/ui/statics/const_generics.rs index 70d9b933a76..7f64f6995a4 100644 --- a/tests/ui/statics/const_generics.rs +++ b/tests/ui/statics/const_generics.rs @@ -11,7 +11,7 @@ //@[opt] compile-flags: -O #![feature(const_refs_to_static)] -#![feature(adt_const_params)] +#![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] static FOO: usize = 42; diff --git a/tests/ui/symbol-names/const-generics-str-demangling.rs b/tests/ui/symbol-names/const-generics-str-demangling.rs index 871f3694e00..87b1fdf8a47 100644 --- a/tests/ui/symbol-names/const-generics-str-demangling.rs +++ b/tests/ui/symbol-names/const-generics-str-demangling.rs @@ -1,7 +1,7 @@ //@ build-fail //@ compile-flags: -C symbol-mangling-version=v0 --crate-name=c //@ normalize-stderr-test: "c\[.*?\]" -> "c[HASH]" -#![feature(adt_const_params, rustc_attrs)] +#![feature(adt_const_params, unsized_const_params, rustc_attrs)] #![allow(incomplete_features)] pub struct Str<const S: &'static str>; diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.rs b/tests/ui/symbol-names/const-generics-structural-demangling.rs index 6c79ed7314c..9f5f31177b3 100644 --- a/tests/ui/symbol-names/const-generics-structural-demangling.rs +++ b/tests/ui/symbol-names/const-generics-structural-demangling.rs @@ -3,10 +3,10 @@ //@ normalize-stderr-test: "c\[[0-9a-f]+\]" -> "c[HASH]" -#![feature(adt_const_params, decl_macro, rustc_attrs)] +#![feature(adt_const_params, unsized_const_params, decl_macro, rustc_attrs)] #![allow(incomplete_features)] -use std::marker::ConstParamTy; +use std::marker::UnsizedConstParamTy; pub struct RefByte<const RB: &'static u8>; @@ -14,7 +14,7 @@ pub struct RefByte<const RB: &'static u8>; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(<c::RefByte<{&123}>>) -impl RefByte<{&123}> {} +impl RefByte<{ &123 }> {} // FIXME(eddyb) this was supposed to be `RefMutZst` with `&mut []`, // but that is currently not allowed in const generics. @@ -24,7 +24,7 @@ pub struct RefZst<const RMZ: &'static [u8; 0]>; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(<c::RefZst<{&[]}>>) -impl RefZst<{&[]}> {} +impl RefZst<{ &[] }> {} pub struct Array3Bytes<const A3B: [u8; 3]>; @@ -32,7 +32,7 @@ pub struct Array3Bytes<const A3B: [u8; 3]>; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(<c::Array3Bytes<{[1, 2, 3]}>>) -impl Array3Bytes<{[1, 2, 3]}> {} +impl Array3Bytes<{ [1, 2, 3] }> {} pub struct TupleByteBool<const TBB: (u8, bool)>; @@ -40,9 +40,9 @@ pub struct TupleByteBool<const TBB: (u8, bool)>; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(<c::TupleByteBool<{(1, false)}>>) -impl TupleByteBool<{(1, false)}> {} +impl TupleByteBool<{ (1, false) }> {} -#[derive(PartialEq, Eq, ConstParamTy)] +#[derive(PartialEq, Eq, UnsizedConstParamTy)] pub enum MyOption<T> { Some(T), None, @@ -56,7 +56,7 @@ pub struct OptionUsize<const OU: MyOption<usize>>; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::None}>>) -impl OptionUsize<{MyOption::None}> {} +impl OptionUsize<{ MyOption::None }> {} // HACK(eddyb) the full mangling is only in `.stderr` because we can normalize // the `core` disambiguator hash away there, but not here. @@ -64,9 +64,9 @@ impl OptionUsize<{MyOption::None}> {} //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::Some(0)}>>) -impl OptionUsize<{MyOption::Some(0)}> {} +impl OptionUsize<{ MyOption::Some(0) }> {} -#[derive(PartialEq, Eq, ConstParamTy)] +#[derive(PartialEq, Eq, UnsizedConstParamTy)] pub struct Foo { s: &'static str, ch: char, @@ -78,12 +78,12 @@ pub struct Foo_<const F: Foo>; //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(<c::Foo_<{c::Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}>>) -impl Foo_<{Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] }}> {} +impl Foo_<{ Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] } }> {} // NOTE(eddyb) this tests specifically the use of disambiguators in field names, // using macros 2.0 hygiene to create a `struct` with conflicting field names. macro duplicate_field_name_test($x:ident) { - #[derive(PartialEq, Eq, ConstParamTy)] + #[derive(PartialEq, Eq, UnsizedConstParamTy)] pub struct Bar { $x: u8, x: u16, @@ -94,7 +94,7 @@ macro duplicate_field_name_test($x:ident) { //~^ ERROR symbol-name //~| ERROR demangling //~| ERROR demangling-alt(<c::Bar_<{c::Bar { x: 123, x: 4096 }}>>) - impl Bar_<{Bar { $x: 123, x: 4096 }}> {} + impl Bar_<{ Bar { $x: 123, x: 4096 } }> {} } duplicate_field_name_test!(x); diff --git a/tests/ui/target-feature/gate.rs b/tests/ui/target-feature/gate.rs index af47e84672f..94d79d56c59 100644 --- a/tests/ui/target-feature/gate.rs +++ b/tests/ui/target-feature/gate.rs @@ -21,6 +21,7 @@ // gate-test-loongarch_target_feature // gate-test-lahfsahf_target_feature // gate-test-prfchw_target_feature +// gate-test-s390x_target_feature #[target_feature(enable = "avx512bw")] //~^ ERROR: currently unstable diff --git a/tests/ui/target-feature/gate.stderr b/tests/ui/target-feature/gate.stderr index 31198f73c20..a69020e6864 100644 --- a/tests/ui/target-feature/gate.stderr +++ b/tests/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:25:18 + --> $DIR/gate.rs:26:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs index fc64381b961..b61a21eab41 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs +++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.rs @@ -18,7 +18,8 @@ trait TraitC {} fn foo<T>() where for<const N: u8 = { T::A }> T: TraitA<AsA = impl TraitB<AsB = impl TraitC>>, - //~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~^ ERROR late-bound const parameters cannot be used currently + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders //~| ERROR `impl Trait` is not allowed in bounds { } diff --git a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr index a4a79413a9b..e891df3f0c0 100644 --- a/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr +++ b/tests/ui/traits/non_lifetime_binders/bad-suggestion-on-missing-assoc.stderr @@ -1,3 +1,9 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/bad-suggestion-on-missing-assoc.rs:20:15 + | +LL | for<const N: u8 = { T::A }> T: TraitA<AsA = impl TraitB<AsB = impl TraitC>>, + | ^ + warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/bad-suggestion-on-missing-assoc.rs:1:12 | @@ -29,6 +35,6 @@ LL | for<const N: u8 = { T::A }> T: TraitA<AsA = impl TraitB<AsB = impl Trai | = note: `impl Trait` is only allowed in arguments and return types of functions and methods -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 3 previous errors; 2 warnings emitted For more information about this error, try `rustc --explain E0562`. diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs index c6bf0dc1f72..13f9f196970 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.rs @@ -4,10 +4,11 @@ pub fn bar() where for<const N: usize = { + //~^ ERROR late-bound const parameters cannot be used currently + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders (||1usize)() }> V: IntoIterator -//~^^^ ERROR defaults for generic parameters are not allowed in `for<...>` binders -//~^^ ERROR cannot find type `V` in this scope +//~^ ERROR cannot find type `V` in this scope { } diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr index edc55a3c8e6..d9e77dec794 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-112547.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `V` in this scope - --> $DIR/binder-defaults-112547.rs:8:4 + --> $DIR/binder-defaults-112547.rs:10:4 | LL | }> V: IntoIterator | ^ not found in this scope @@ -9,6 +9,12 @@ help: you might be missing a type parameter LL | pub fn bar<V>() | +++ +error: late-bound const parameters cannot be used currently + --> $DIR/binder-defaults-112547.rs:6:15 + | +LL | for<const N: usize = { + | ^ + warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/binder-defaults-112547.rs:1:12 | @@ -23,10 +29,12 @@ error: defaults for generic parameters are not allowed in `for<...>` binders | LL | for<const N: usize = { | _________^ +LL | | +LL | | LL | | (||1usize)() LL | | }> V: IntoIterator | |_^ -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 3 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs index f33da416ad8..bdfe41ca11b 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.rs @@ -5,8 +5,9 @@ fn fun() where for<T = (), const N: usize = 1> ():, -//~^ ERROR defaults for generic parameters are not allowed in `for<...>` binders -//~| ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~^ ERROR late-bound const parameters cannot be used currently + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders + //~| ERROR defaults for generic parameters are not allowed in `for<...>` binders {} fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr index 7fe82f1f097..947dd3a73bf 100644 --- a/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr +++ b/tests/ui/traits/non_lifetime_binders/binder-defaults-119489.stderr @@ -1,3 +1,9 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/binder-defaults-119489.rs:7:23 + | +LL | for<T = (), const N: usize = 1> ():, + | ^ + warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/binder-defaults-119489.rs:1:12 | @@ -27,5 +33,5 @@ error: defaults for generic parameters are not allowed in `for<...>` binders LL | for<T = (), const N: usize = 1> ():, | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 2 previous errors; 2 warnings emitted +error: aborting due to 3 previous errors; 2 warnings emitted diff --git a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs new file mode 100644 index 00000000000..2d44388f875 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.rs @@ -0,0 +1,11 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +fn b() +where + for<const C: usize> [(); C]: Copy, + //~^ ERROR late-bound const parameters cannot be used currently +{ +} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr new file mode 100644 index 00000000000..136d533a03c --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/late-const-param-wf.stderr @@ -0,0 +1,17 @@ +error: late-bound const parameters cannot be used currently + --> $DIR/late-const-param-wf.rs:6:15 + | +LL | for<const C: usize> [(); C]: Copy, + | ^ + +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/late-const-param-wf.rs:1:12 + | +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: aborting due to 1 previous error; 1 warning emitted + diff --git a/tests/ui/try-trait/bad-interconversion.stderr b/tests/ui/try-trait/bad-interconversion.stderr index c30b6334fed..642a93d64e2 100644 --- a/tests/ui/try-trait/bad-interconversion.stderr +++ b/tests/ui/try-trait/bad-interconversion.stderr @@ -23,9 +23,7 @@ LL | Some(3)?; | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>` | = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>` - = help: the following other types implement trait `FromResidual<R>`: - `Result<T, F>` implements `FromResidual<Result<Infallible, E>>` - `Result<T, F>` implements `FromResidual<Yeet<E>>` + = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>` error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` --> $DIR/bad-interconversion.rs:17:31 @@ -36,9 +34,7 @@ LL | Ok(ControlFlow::Break(123)?) | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>` | = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>` - = help: the following other types implement trait `FromResidual<R>`: - `Result<T, F>` implements `FromResidual<Result<Infallible, E>>` - `Result<T, F>` implements `FromResidual<Yeet<E>>` + = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/bad-interconversion.rs:22:22 @@ -49,9 +45,7 @@ LL | Some(Err("hello")?) | ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information | = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>` - = help: the following other types implement trait `FromResidual<R>`: - `Option<T>` implements `FromResidual<Yeet<()>>` - `Option<T>` implements `FromResidual` + = help: the trait `FromResidual` is implemented for `Option<T>` error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` --> $DIR/bad-interconversion.rs:27:33 @@ -62,9 +56,7 @@ LL | Some(ControlFlow::Break(123)?) | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>` | = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>` - = help: the following other types implement trait `FromResidual<R>`: - `Option<T>` implements `FromResidual<Yeet<()>>` - `Option<T>` implements `FromResidual` + = help: the trait `FromResidual` is implemented for `Option<T>` error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` --> $DIR/bad-interconversion.rs:32:39 diff --git a/tests/ui/try-trait/option-to-result.stderr b/tests/ui/try-trait/option-to-result.stderr index 2d97226275d..8055b2a0b04 100644 --- a/tests/ui/try-trait/option-to-result.stderr +++ b/tests/ui/try-trait/option-to-result.stderr @@ -8,9 +8,7 @@ LL | a?; | ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>` | = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>` - = help: the following other types implement trait `FromResidual<R>`: - `Result<T, F>` implements `FromResidual<Result<Infallible, E>>` - `Result<T, F>` implements `FromResidual<Yeet<E>>` + = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>` error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` --> $DIR/option-to-result.rs:11:6 @@ -22,9 +20,7 @@ LL | a?; | ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information | = help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>` - = help: the following other types implement trait `FromResidual<R>`: - `Option<T>` implements `FromResidual<Yeet<()>>` - `Option<T>` implements `FromResidual` + = help: the trait `FromResidual` is implemented for `Option<T>` error: aborting due to 2 previous errors diff --git a/tests/ui/try-trait/try-on-option.stderr b/tests/ui/try-trait/try-on-option.stderr index 84a51a078af..15d0b28ddc1 100644 --- a/tests/ui/try-trait/try-on-option.stderr +++ b/tests/ui/try-trait/try-on-option.stderr @@ -8,9 +8,7 @@ LL | x?; | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>` | = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>` - = help: the following other types implement trait `FromResidual<R>`: - `Result<T, F>` implements `FromResidual<Result<Infallible, E>>` - `Result<T, F>` implements `FromResidual<Yeet<E>>` + = help: the trait `FromResidual<Result<Infallible, E>>` is implemented for `Result<T, F>` error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option.rs:11:6 diff --git a/tests/ui/typeck/ice-unexpected-region-123863.stderr b/tests/ui/typeck/ice-unexpected-region-123863.stderr index 08f1ede95b4..0479f134a38 100644 --- a/tests/ui/typeck/ice-unexpected-region-123863.stderr +++ b/tests/ui/typeck/ice-unexpected-region-123863.stderr @@ -9,6 +9,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error: `&'static str` is forbidden as the type of a const generic parameter --> $DIR/ice-unexpected-region-123863.rs:3:27 @@ -21,6 +25,10 @@ help: add `#![feature(adt_const_params)]` to the crate attributes to enable more | LL + #![feature(adt_const_params)] | +help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait + | +LL + #![feature(unsized_const_params)] + | error[E0223]: ambiguous associated type --> $DIR/ice-unexpected-region-123863.rs:5:5 diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr index e30cb8ff921..8d5b377988c 100644 --- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -26,8 +26,8 @@ LL | trait Trait: 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: - R S + R = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object @@ -48,8 +48,8 @@ LL | trait Trait: 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: - R S + R = note: required for the cast from `&R` to `&dyn Trait` error: aborting due to 3 previous errors diff --git a/triagebot.toml b/triagebot.toml index 5335cf4e4bf..5c5aa475385 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -905,7 +905,7 @@ cc = ["@kobzol"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "jhpratt", "oli-obk"] +users_on_vacation = ["jyn514", "jhpratt", "oli-obk", "michaelwoerister"] [assign.adhoc_groups] compiler-team = [ |
