diff options
873 files changed, 12958 insertions, 14192 deletions
diff --git a/.github/ISSUE_TEMPLATE/regression.md b/.github/ISSUE_TEMPLATE/regression.md new file mode 100644 index 00000000000..ffab883987c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/regression.md @@ -0,0 +1,68 @@ +--- +name: Regression +about: Report something that unexpectedly changed between Rust versions. +labels: C-bug regression-untriaged +--- +<!-- +Thank you for filing a regression report! 🐛 A regression is something that changed between versions of Rust but was not supposed to. + +Please provide a short summary of the regression, along with any information you feel is relevant to replicate it. +--> + +### Code + +I tried this code: + +```rust +<code> +``` + +I expected to see this happen: *explanation* + +Instead, this happened: *explanation* + +### Version it worked on + +<!-- +Provide the most recent version this worked on, for example: + +It most recently worked on: Rust 1.47 +--> + +It most recently worked on: <!-- version --> + +### Version with regression + +<!-- +Provide the version you are using that has the regression. +--> + +`rustc --version --verbose`: +``` +<version> +``` + +<!-- +Did the compiler crash? If so, please provide a backtrace. +--> + +### Backtrace +<!-- +Include a backtrace in the code block by setting `RUST_BACKTRACE=1` in your +environment. E.g. `RUST_BACKTRACE=1 cargo build`. +--> +<details><summary>Backtrace</summary> +<p> + +``` +<backtrace> +``` + +</p> +</details> + +<!-- +If you know when this regression occurred, please add a line like below, replacing `{channel}` with one of stable, beta, or nightly. + +@rustbot modify labels: +regression-from-stable-to-{channel} -regression-untriaged +--> diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 23058b7a808..6025808eb61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,6 +89,9 @@ jobs: - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh if: success() && !env.SKIP_JOB @@ -300,6 +303,20 @@ jobs: NO_LLVM_ASSERTIONS: 1 NO_DEBUG_ASSERTIONS: 1 os: macos-latest + - name: dist-aarch64-apple + env: + SCRIPT: "./x.py dist --stage 2" + RUST_CONFIGURE_ARGS: "--build=x86_64-apple-darwin --host=aarch64-apple-darwin --target=aarch64-apple-darwin --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false" + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_12.2.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + JEMALLOC_SYS_WITH_LG_PAGE: 14 + os: macos-latest - name: x86_64-msvc-1 env: RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --enable-profiler" @@ -369,7 +386,7 @@ jobs: os: windows-latest-xl - name: dist-x86_64-msvc env: - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools --enable-profiler" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler" SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl @@ -379,6 +396,12 @@ jobs: SCRIPT: python x.py dist DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl + - name: dist-aarch64-msvc + env: + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-msvc --host=aarch64-pc-windows-msvc --enable-full-tools --enable-profiler" + SCRIPT: python x.py dist + DIST_REQUIRE_ALL_TOOLS: 0 + os: windows-latest-xl - name: dist-i686-mingw env: RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler" @@ -437,6 +460,9 @@ jobs: - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh if: success() && !env.SKIP_JOB @@ -544,6 +570,9 @@ jobs: - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh if: success() && !env.SKIP_JOB @@ -648,6 +677,9 @@ jobs: - name: install sccache run: src/ci/scripts/install-sccache.sh if: success() && !env.SKIP_JOB + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + if: success() && !env.SKIP_JOB - name: install clang run: src/ci/scripts/install-clang.sh if: success() && !env.SKIP_JOB diff --git a/.gitmodules b/.gitmodules index d460b6508f6..984113151de 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,7 +37,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/11.0-2020-09-22 + branch = rustc/11.0-2020-10-12 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/Cargo.lock b/Cargo.lock index 63c4fcf9e67..0d2170a9927 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -132,13 +132,13 @@ checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "backtrace" -version = "0.3.50" +version = "0.3.53" dependencies = [ "addr2line", - "cfg-if", + "cfg-if 1.0.0", "libc", "miniz_oxide", - "object", + "object 0.21.1", "rustc-demangle", ] @@ -243,6 +243,7 @@ dependencies = [ "anyhow", "flate2", "hex 0.4.2", + "num_cpus", "rayon", "serde", "serde_json", @@ -294,7 +295,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da" [[package]] name = "cargo" -version = "0.49.0" +version = "0.50.0" dependencies = [ "anyhow", "atty", @@ -305,7 +306,7 @@ dependencies = [ "clap", "core-foundation", "crates-io", - "crossbeam-utils 0.7.2", + "crossbeam-utils 0.8.0", "crypto-hash", "curl", "curl-sys", @@ -441,6 +442,12 @@ dependencies = [ ] [[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] name = "chalk-derive" version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -670,6 +677,12 @@ dependencies = [ ] [[package]] +name = "const_fn" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce90df4c658c62f12d78f7508cf92f9173e5184a539c10bfe54a3107b3ffd0f2" + +[[package]] name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -722,17 +735,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] name = "crossbeam-channel" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" dependencies = [ - "cfg-if", "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] @@ -753,7 +766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils 0.7.2", "lazy_static", "maybe-uninit", @@ -776,7 +789,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils 0.7.2", "maybe-uninit", ] @@ -787,7 +800,7 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "lazy_static", ] @@ -798,7 +811,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec91540d98355f690a86367e566ecad2e9e579f230230eb7c21398372be73ea5" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "const_fn", "lazy_static", ] @@ -928,7 +953,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "dirs-sys", ] @@ -1070,7 +1095,7 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "redox_syscall", "winapi 0.3.9", @@ -1088,7 +1113,7 @@ version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "crc32fast", "libc", "libz-sys", @@ -1219,7 +1244,7 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi", ] @@ -1230,7 +1255,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi", ] @@ -1248,9 +1273,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.8" +version = "0.13.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ac22e49b7d886b6802c66662b12609452248b1bc9e87d6d83ecea3db96f557" +checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224" dependencies = [ "bitflags", "libc", @@ -1668,9 +1693,9 @@ dependencies = [ [[package]] name = "libgit2-sys" -version = "0.12.9+1.0.1" +version = "0.12.14+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b33bf3d9d4c45b48ae1ea7c334be69994624dc0a69f833d5d9f7605f24b552b" +checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" dependencies = [ "cc", "libc", @@ -1692,9 +1717,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafa907407504b0e683786d4aba47acf250f114d37357d56608333fd167dd0fc" +checksum = "ca46220853ba1c512fc82826d0834d87b06bcd3c2a42241b7de72f3d2fe17056" dependencies = [ "cc", "libc", @@ -1719,6 +1744,10 @@ dependencies = [ [[package]] name = "linkchecker" version = "0.1.0" +dependencies = [ + "once_cell", + "regex", +] [[package]] name = "linked-hash-map" @@ -1759,7 +1788,7 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -1989,7 +2018,7 @@ version = "0.6.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "fuchsia-zircon", "fuchsia-zircon-sys", "iovec", @@ -2070,7 +2099,7 @@ version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "winapi 0.3.9", ] @@ -2122,6 +2151,12 @@ dependencies = [ ] [[package]] +name = "object" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37fd5004feb2ce328a52b0b3d01dbf4ffff72583493900ed15f22d4111c51693" + +[[package]] name = "once_cell" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2164,7 +2199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4" dependencies = [ "bitflags", - "cfg-if", + "cfg-if 0.1.10", "foreign-types", "lazy_static", "libc", @@ -2179,9 +2214,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-src" -version = "111.10.2+1.1.1g" +version = "111.12.0+1.1.1h" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a287fdb22e32b5b60624d4a5a7a02dbe82777f730ec0dbc42a0554326fef5a70" +checksum = "858a4132194f8570a7ee9eb8629e85b23cbc4565f2d4a162e87556e5956abf61" dependencies = [ "cc", ] @@ -2221,14 +2256,14 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] name = "panic_abort" version = "0.0.0" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "compiler_builtins", "core", "libc", @@ -2239,7 +2274,7 @@ name = "panic_unwind" version = "0.0.0" dependencies = [ "alloc", - "cfg-if", + "cfg-if 0.1.10", "compiler_builtins", "core", "libc", @@ -2302,7 +2337,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "cloudabi 0.0.3", "libc", "redox_syscall", @@ -2317,7 +2352,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "cloudabi 0.0.3", "libc", "redox_syscall", @@ -2331,7 +2366,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "cloudabi 0.1.0", "instant", "libc", @@ -3035,7 +3070,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14ffd17a37e00d77926a0713f191c59ff3aeb2b551a024c7cfffce14bab79be8" dependencies = [ "bitflags", - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils 0.7.2", "ena", "indexmap", @@ -3211,7 +3246,7 @@ version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c267f15c3cfc82a8a441d2bf86bcccf299d1eb625822468e3d8ee6f7c5a1c89" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "md-5", "rustc-ap-rustc_arena", "rustc-ap-rustc_data_structures", @@ -3337,7 +3372,6 @@ dependencies = [ name = "rustc_arena" version = "0.0.0" dependencies = [ - "rustc_data_structures", "smallvec 1.4.2", ] @@ -3504,7 +3538,7 @@ version = "0.0.0" dependencies = [ "arrayvec", "bitflags", - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils 0.7.2", "ena", "indexmap", @@ -4055,7 +4089,7 @@ dependencies = [ name = "rustc_span" version = "0.0.0" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "md-5", "rustc_arena", "rustc_data_structures", @@ -4416,7 +4450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1" dependencies = [ "block-buffer 0.9.0", - "cfg-if", + "cfg-if 0.1.10", "cpuid-bool", "digest 0.9.0", "opaque-debug 0.3.0", @@ -4502,7 +4536,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "redox_syscall", "winapi 0.3.9", @@ -4521,7 +4555,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21ccb4c06ec57bc82d0f610f1a2963d7648700e43a6f513e564b9c89f7991786" dependencies = [ "cc", - "cfg-if", + "cfg-if 0.1.10", "libc", "psm", "winapi 0.3.9", @@ -4533,7 +4567,7 @@ version = "0.0.0" dependencies = [ "addr2line", "alloc", - "cfg-if", + "cfg-if 0.1.10", "compiler_builtins", "core", "dlmalloc", @@ -4542,7 +4576,7 @@ dependencies = [ "hermit-abi", "libc", "miniz_oxide", - "object", + "object 0.20.0", "panic_abort", "panic_unwind", "profiler_builtins", @@ -4675,7 +4709,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "rand", "redox_syscall", @@ -4735,7 +4769,7 @@ dependencies = [ name = "test" version = "0.0.0" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "core", "getopts", "libc", @@ -5067,9 +5101,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" dependencies = [ "serde", ] @@ -5080,7 +5114,7 @@ version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d79ca061b032d6ce30c660fded31189ca0b9922bf483cd70759f13a2d86786c" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "tracing-attributes", "tracing-core", ] @@ -5277,7 +5311,7 @@ name = "unwind" version = "0.0.0" dependencies = [ "cc", - "cfg-if", + "cfg-if 0.1.10", "compiler_builtins", "core", "libc", diff --git a/compiler/rustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml index 41701f3255f..29caa852ed4 100644 --- a/compiler/rustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -5,5 +5,4 @@ version = "0.0.0" edition = "2018" [dependencies] -rustc_data_structures = { path = "../rustc_data_structures" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 166f7f53c41..c051c607ff2 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -16,7 +16,6 @@ #![feature(maybe_uninit_slice)] #![cfg_attr(test, feature(test))] -use rustc_data_structures::cold_path; use smallvec::SmallVec; use std::alloc::Layout; @@ -27,6 +26,12 @@ use std::mem::{self, MaybeUninit}; use std::ptr; use std::slice; +#[inline(never)] +#[cold] +pub fn cold_path<F: FnOnce() -> R, R>(f: F) -> R { + f() +} + /// An arena that can hold objects of only one type. pub struct TypedArena<T> { /// A pointer to the next object to be allocated. diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 8d9d4123c79..8f156aea2ff 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -167,13 +167,6 @@ pub enum GenericArgs { } impl GenericArgs { - pub fn is_parenthesized(&self) -> bool { - match *self { - Parenthesized(..) => true, - _ => false, - } - } - pub fn is_angle_bracketed(&self) -> bool { match *self { AngleBracketed(..) => true, @@ -857,13 +850,6 @@ impl BinOpKind { } } - pub fn is_shift(&self) -> bool { - match *self { - BinOpKind::Shl | BinOpKind::Shr => true, - _ => false, - } - } - pub fn is_comparison(&self) -> bool { use BinOpKind::*; // Note for developers: please keep this as is; @@ -873,11 +859,6 @@ impl BinOpKind { And | Or | Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr => false, } } - - /// Returns `true` if the binary operator takes its arguments by value - pub fn is_by_value(&self) -> bool { - !self.is_comparison() - } } pub type BinOp = Spanned<BinOpKind>; @@ -896,14 +877,6 @@ pub enum UnOp { } impl UnOp { - /// Returns `true` if the unary operator takes its argument by value - pub fn is_by_value(u: UnOp) -> bool { - match u { - UnOp::Neg | UnOp::Not => true, - _ => false, - } - } - pub fn to_string(op: UnOp) -> &'static str { match op { UnOp::Deref => "*", @@ -1753,13 +1726,6 @@ impl IntTy { } } - pub fn val_to_string(&self, val: i128) -> String { - // Cast to a `u128` so we can correctly print `INT128_MIN`. All integral types - // are parsed as `u128`, so we wouldn't want to print an extra negative - // sign. - format!("{}{}", val as u128, self.name_str()) - } - pub fn bit_width(&self) -> Option<u64> { Some(match *self { IntTy::Isize => return None, @@ -1818,10 +1784,6 @@ impl UintTy { } } - pub fn val_to_string(&self, val: u128) -> String { - format!("{}{}", val, self.name_str()) - } - pub fn bit_width(&self) -> Option<u64> { Some(match *self { UintTy::Usize => return None, @@ -1884,6 +1846,16 @@ impl Clone for Ty { } } +impl Ty { + pub fn peel_refs(&self) -> &Self { + let mut final_ty = self; + while let TyKind::Rptr(_, MutTy { ty, .. }) = &final_ty.kind { + final_ty = &ty; + } + final_ty + } +} + #[derive(Clone, Encodable, Decodable, Debug)] pub struct BareFnTy { pub unsafety: Unsafe, diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index 2782869fb88..8351be222f6 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -101,11 +101,6 @@ impl NestedMetaItem { self.meta_item().is_some() } - /// Returns `true` if the variant is `Literal`. - pub fn is_literal(&self) -> bool { - self.literal().is_some() - } - /// Returns `true` if `self` is a `MetaItem` and the meta item is a word. pub fn is_word(&self) -> bool { self.meta_item().map_or(false, |meta_item| meta_item.is_word()) @@ -232,10 +227,6 @@ impl MetaItem { pub fn is_value_str(&self) -> bool { self.value_str().is_some() } - - pub fn is_meta_item_list(&self) -> bool { - self.meta_item_list().is_some() - } } impl AttrItem { diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index d5b3e87adc3..ad9c7391939 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -54,16 +54,6 @@ pub enum DelimToken { NoDelim, } -impl DelimToken { - pub fn len(self) -> usize { - if self == NoDelim { 0 } else { 1 } - } - - pub fn is_empty(self) -> bool { - self == NoDelim - } -} - #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] pub enum LitKind { Bool, // AST only, must never appear in a `Token` @@ -810,10 +800,10 @@ impl Nonterminal { if let ExpnKind::Macro(_, macro_name) = orig_span.ctxt().outer_expn_data().kind { let filename = source_map.span_to_filename(orig_span); if let FileName::Real(RealFileName::Named(path)) = filename { - let matches_prefix = |prefix| { - // Check for a path that ends with 'prefix*/src/lib.rs' + let matches_prefix = |prefix, filename| { + // Check for a path that ends with 'prefix*/src/<filename>' let mut iter = path.components().rev(); - iter.next().and_then(|p| p.as_os_str().to_str()) == Some("lib.rs") + iter.next().and_then(|p| p.as_os_str().to_str()) == Some(filename) && iter.next().and_then(|p| p.as_os_str().to_str()) == Some("src") && iter .next() @@ -821,14 +811,25 @@ impl Nonterminal { .map_or(false, |p| p.starts_with(prefix)) }; - if (macro_name == sym::impl_macros && matches_prefix("time-macros-impl")) - || (macro_name == sym::arrays && matches_prefix("js-sys")) + if (macro_name == sym::impl_macros + && matches_prefix("time-macros-impl", "lib.rs")) + || (macro_name == sym::arrays && matches_prefix("js-sys", "lib.rs")) { let snippet = source_map.span_to_snippet(orig_span); if snippet.as_deref() == Ok("$name") { return Some((*ident, *is_raw)); } } + + if macro_name == sym::tuple_from_req + && (matches_prefix("actix-web", "extract.rs") + || matches_prefix("actori-web", "extract.rs")) + { + let snippet = source_map.span_to_snippet(orig_span); + if snippet.as_deref() == Ok("$T") { + return Some((*ident, *is_raw)); + } + } } } } diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index f201f0b5c66..8acb6b2f375 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -295,12 +295,6 @@ impl TokenStream { .collect(), )) } - - pub fn map<F: FnMut(TokenTree) -> TokenTree>(self, mut f: F) -> TokenStream { - TokenStream(Lrc::new( - self.0.iter().map(|(tree, is_joint)| (f(tree.clone()), *is_joint)).collect(), - )) - } } // 99.5%+ of the time we have 1 or 2 elements in this vector. diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 2ee94965756..be5516ef471 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -231,7 +231,6 @@ impl AssocOp { } } -pub const PREC_RESET: i8 = -100; pub const PREC_CLOSURE: i8 = -40; pub const PREC_JUMP: i8 = -30; pub const PREC_RANGE: i8 = -10; diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 4676ad5c31f..2d2caa7a808 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -985,7 +985,7 @@ impl<'hir> LoweringContext<'_, 'hir> { asm::InlineAsmReg::parse( sess.asm_arch?, |feature| sess.target_features.contains(&Symbol::intern(feature)), - &sess.target.target, + &sess.target, s, ) .map_err(|e| { diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 232ee35c4f7..d9791fe743c 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -796,7 +796,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { fn visit_expr(&mut self, expr: &'a Expr) { match &expr.kind { - ExprKind::LlvmInlineAsm(..) if !self.session.target.target.options.allow_asm => { + ExprKind::LlvmInlineAsm(..) if !self.session.target.options.allow_asm => { struct_span_err!( self.session, expr.span, diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs index ca7f127ced6..95f969d7691 100644 --- a/compiler/rustc_ast_pretty/src/pp.rs +++ b/compiler/rustc_ast_pretty/src/pp.rs @@ -170,17 +170,11 @@ pub enum Token { impl Token { crate fn is_eof(&self) -> bool { - match *self { - Token::Eof => true, - _ => false, - } + matches!(self, Token::Eof) } pub fn is_hardbreak_tok(&self) -> bool { - match *self { - Token::Break(BreakToken { offset: 0, blank_space: bs }) if bs == SIZE_INFINITY => true, - _ => false, - } + matches!(self, Token::Break(BreakToken { offset: 0, blank_space: SIZE_INFINITY })) } } @@ -491,12 +485,9 @@ impl Printer { } fn get_top(&mut self) -> PrintStackElem { - match self.print_stack.last() { - Some(el) => *el, - None => { - PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) } - } - } + *self.print_stack.last().unwrap_or({ + &PrintStackElem { offset: 0, pbreak: PrintStackBreak::Broken(Breaks::Inconsistent) } + }) } fn print_begin(&mut self, b: BeginToken, l: isize) { diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs new file mode 100644 index 00000000000..b34ea41ab55 --- /dev/null +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -0,0 +1,104 @@ +#[cfg(test)] +mod tests; + +pub mod state; +pub use state::{print_crate, AnnNode, Comments, PpAnn, PrintState, State}; + +use rustc_ast as ast; +use rustc_ast::token::{Nonterminal, Token, TokenKind}; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; + +pub fn nonterminal_to_string_no_extra_parens(nt: &Nonterminal) -> String { + let state = State::without_insert_extra_parens(); + state.nonterminal_to_string(nt) +} + +pub fn nonterminal_to_string(nt: &Nonterminal) -> String { + State::new().nonterminal_to_string(nt) +} + +/// Print the token kind precisely, without converting `$crate` into its respective crate name. +pub fn token_kind_to_string(tok: &TokenKind) -> String { + State::new().token_kind_to_string(tok) +} + +/// Print the token precisely, without converting `$crate` into its respective crate name. +pub fn token_to_string(token: &Token) -> String { + State::new().token_to_string(token) +} + +pub fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String { + State::new().token_to_string_ext(token, convert_dollar_crate) +} + +pub fn ty_to_string(ty: &ast::Ty) -> String { + State::new().ty_to_string(ty) +} + +pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String { + State::new().bounds_to_string(bounds) +} + +pub fn pat_to_string(pat: &ast::Pat) -> String { + State::new().pat_to_string(pat) +} + +pub fn expr_to_string(e: &ast::Expr) -> String { + State::new().expr_to_string(e) +} + +pub fn tt_to_string(tt: &TokenTree) -> String { + State::new().tt_to_string(tt) +} + +pub fn tts_to_string(tokens: &TokenStream) -> String { + State::new().tts_to_string(tokens) +} + +pub fn stmt_to_string(stmt: &ast::Stmt) -> String { + State::new().stmt_to_string(stmt) +} + +pub fn item_to_string(i: &ast::Item) -> String { + State::new().item_to_string(i) +} + +pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String { + State::new().generic_params_to_string(generic_params) +} + +pub fn path_to_string(p: &ast::Path) -> String { + State::new().path_to_string(p) +} + +pub fn path_segment_to_string(p: &ast::PathSegment) -> String { + State::new().path_segment_to_string(p) +} + +pub fn vis_to_string(v: &ast::Visibility) -> String { + State::new().vis_to_string(v) +} + +pub fn block_to_string(blk: &ast::Block) -> String { + State::new().block_to_string(blk) +} + +pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { + State::new().meta_list_item_to_string(li) +} + +pub fn attr_item_to_string(ai: &ast::AttrItem) -> String { + State::new().attr_item_to_string(ai) +} + +pub fn attribute_to_string(attr: &ast::Attribute) -> String { + State::new().attribute_to_string(attr) +} + +pub fn param_to_string(arg: &ast::Param) -> String { + State::new().param_to_string(arg) +} + +pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { + State::new().to_string(f) +} diff --git a/compiler/rustc_ast_pretty/src/pprust.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index d16b541c699..9aa066370bb 100644 --- a/compiler/rustc_ast_pretty/src/pprust.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -20,9 +20,6 @@ use rustc_span::{BytePos, FileName, Span}; use std::borrow::Cow; -#[cfg(test)] -mod tests; - pub enum MacHeader<'a> { Path(&'a ast::Path), Keyword(&'static str), @@ -91,6 +88,13 @@ pub struct State<'a> { comments: Option<Comments<'a>>, ann: &'a (dyn PpAnn + 'a), is_expanded: bool, + // If `true`, additional parenthesis (separate from `ExprKind::Paren`) + // are inserted to ensure that proper precedence is preserved + // in the pretty-printed output. + // + // This is usually `true`, except when performing the pretty-print/reparse + // check in `nt_to_tokenstream` + insert_extra_parens: bool, } crate const INDENT_UNIT: usize = 4; @@ -112,6 +116,7 @@ pub fn print_crate<'a>( comments: Some(Comments::new(sm, filename, input)), ann, is_expanded, + insert_extra_parens: true, }; if is_expanded && has_injected_crate { @@ -142,13 +147,6 @@ pub fn print_crate<'a>( s.s.eof() } -pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { - let mut printer = - State { s: pp::mk_printer(), comments: None, ann: &NoAnn, is_expanded: false }; - f(&mut printer); - printer.s.eof() -} - // This makes printed token streams look slightly nicer, // and also addresses some specific regressions described in #63896 and #73345. fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { @@ -231,173 +229,8 @@ pub fn literal_to_string(lit: token::Lit) -> String { out } -/// Print the token kind precisely, without converting `$crate` into its respective crate name. -pub fn token_kind_to_string(tok: &TokenKind) -> String { - token_kind_to_string_ext(tok, None) -} - -fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option<Span>) -> String { - match *tok { - token::Eq => "=".to_string(), - token::Lt => "<".to_string(), - token::Le => "<=".to_string(), - token::EqEq => "==".to_string(), - token::Ne => "!=".to_string(), - token::Ge => ">=".to_string(), - token::Gt => ">".to_string(), - token::Not => "!".to_string(), - token::Tilde => "~".to_string(), - token::OrOr => "||".to_string(), - token::AndAnd => "&&".to_string(), - token::BinOp(op) => binop_to_string(op).to_string(), - token::BinOpEq(op) => format!("{}=", binop_to_string(op)), - - /* Structural symbols */ - token::At => "@".to_string(), - token::Dot => ".".to_string(), - token::DotDot => "..".to_string(), - token::DotDotDot => "...".to_string(), - token::DotDotEq => "..=".to_string(), - token::Comma => ",".to_string(), - token::Semi => ";".to_string(), - token::Colon => ":".to_string(), - token::ModSep => "::".to_string(), - token::RArrow => "->".to_string(), - token::LArrow => "<-".to_string(), - token::FatArrow => "=>".to_string(), - token::OpenDelim(token::Paren) => "(".to_string(), - token::CloseDelim(token::Paren) => ")".to_string(), - token::OpenDelim(token::Bracket) => "[".to_string(), - token::CloseDelim(token::Bracket) => "]".to_string(), - token::OpenDelim(token::Brace) => "{".to_string(), - token::CloseDelim(token::Brace) => "}".to_string(), - token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(), - token::Pound => "#".to_string(), - token::Dollar => "$".to_string(), - token::Question => "?".to_string(), - token::SingleQuote => "'".to_string(), - - /* Literals */ - token::Literal(lit) => literal_to_string(lit), - - /* Name components */ - token::Ident(s, is_raw) => IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string(), - token::Lifetime(s) => s.to_string(), - - /* Other */ - token::DocComment(comment_kind, attr_style, data) => { - doc_comment_to_string(comment_kind, attr_style, data) - } - token::Eof => "<eof>".to_string(), - - token::Interpolated(ref nt) => nonterminal_to_string(nt), - } -} - -/// Print the token precisely, without converting `$crate` into its respective crate name. -pub fn token_to_string(token: &Token) -> String { - token_to_string_ext(token, false) -} - -fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String { - let convert_dollar_crate = convert_dollar_crate.then_some(token.span); - token_kind_to_string_ext(&token.kind, convert_dollar_crate) -} - -pub fn nonterminal_to_string(nt: &Nonterminal) -> String { - match *nt { - token::NtExpr(ref e) => expr_to_string(e), - token::NtMeta(ref e) => attr_item_to_string(e), - token::NtTy(ref e) => ty_to_string(e), - token::NtPath(ref e) => path_to_string(e), - token::NtItem(ref e) => item_to_string(e), - token::NtBlock(ref e) => block_to_string(e), - token::NtStmt(ref e) => stmt_to_string(e), - token::NtPat(ref e) => pat_to_string(e), - token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(), - token::NtLifetime(e) => e.to_string(), - token::NtLiteral(ref e) => expr_to_string(e), - token::NtTT(ref tree) => tt_to_string(tree), - token::NtVis(ref e) => vis_to_string(e), - } -} - -pub fn ty_to_string(ty: &ast::Ty) -> String { - to_string(|s| s.print_type(ty)) -} - -pub fn bounds_to_string(bounds: &[ast::GenericBound]) -> String { - to_string(|s| s.print_type_bounds("", bounds)) -} - -pub fn pat_to_string(pat: &ast::Pat) -> String { - to_string(|s| s.print_pat(pat)) -} - -pub fn expr_to_string(e: &ast::Expr) -> String { - to_string(|s| s.print_expr(e)) -} - -pub fn tt_to_string(tt: &TokenTree) -> String { - to_string(|s| s.print_tt(tt, false)) -} - -pub fn tts_to_string(tokens: &TokenStream) -> String { - to_string(|s| s.print_tts(tokens, false)) -} - -pub fn stmt_to_string(stmt: &ast::Stmt) -> String { - to_string(|s| s.print_stmt(stmt)) -} - -pub fn item_to_string(i: &ast::Item) -> String { - to_string(|s| s.print_item(i)) -} - -pub fn generic_params_to_string(generic_params: &[ast::GenericParam]) -> String { - to_string(|s| s.print_generic_params(generic_params)) -} - -pub fn path_to_string(p: &ast::Path) -> String { - to_string(|s| s.print_path(p, false, 0)) -} - -pub fn path_segment_to_string(p: &ast::PathSegment) -> String { - to_string(|s| s.print_path_segment(p, false)) -} - -pub fn vis_to_string(v: &ast::Visibility) -> String { - to_string(|s| s.print_visibility(v)) -} - -fn block_to_string(blk: &ast::Block) -> String { - to_string(|s| { - // Containing cbox, will be closed by `print_block` at `}`. - s.cbox(INDENT_UNIT); - // Head-ibox, will be closed by `print_block` after `{`. - s.ibox(0); - s.print_block(blk) - }) -} - -pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { - to_string(|s| s.print_meta_list_item(li)) -} - -fn attr_item_to_string(ai: &ast::AttrItem) -> String { - to_string(|s| s.print_attr_item(ai, ai.path.span)) -} - -pub fn attribute_to_string(attr: &ast::Attribute) -> String { - to_string(|s| s.print_attribute(attr)) -} - -pub fn param_to_string(arg: &ast::Param) -> String { - to_string(|s| s.print_param(arg, false)) -} - fn visibility_qualified(vis: &ast::Visibility, s: &str) -> String { - format!("{}{}", to_string(|s| s.print_visibility(vis)), s) + format!("{}{}", State::new().to_string(|s| s.print_visibility(vis)), s) } impl std::ops::Deref for State<'_> { @@ -414,6 +247,7 @@ impl std::ops::DerefMut for State<'_> { } pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut { + fn insert_extra_parens(&self) -> bool; fn comments(&mut self) -> &mut Option<Comments<'a>>; fn print_ident(&mut self, ident: Ident); fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool); @@ -679,7 +513,8 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere fn print_tt(&mut self, tt: &TokenTree, convert_dollar_crate: bool) { match tt { TokenTree::Token(token) => { - self.word(token_to_string_ext(&token, convert_dollar_crate)); + let token_str = self.token_to_string_ext(&token, convert_dollar_crate); + self.word(token_str); if let token::DocComment(..) = token.kind { self.hardbreak() } @@ -745,14 +580,20 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere self.space(); } } - _ => self.word(token_kind_to_string(&token::OpenDelim(delim))), + _ => { + let token_str = self.token_kind_to_string(&token::OpenDelim(delim)); + self.word(token_str) + } } self.ibox(0); self.print_tts(tts, convert_dollar_crate); self.end(); match delim { DelimToken::Brace => self.bclose(span), - _ => self.word(token_kind_to_string(&token::CloseDelim(delim))), + _ => { + let token_str = self.token_kind_to_string(&token::CloseDelim(delim)); + self.word(token_str) + } } } @@ -818,9 +659,190 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere } } } + + fn nonterminal_to_string(&self, nt: &Nonterminal) -> String { + match *nt { + token::NtExpr(ref e) => self.expr_to_string(e), + token::NtMeta(ref e) => self.attr_item_to_string(e), + token::NtTy(ref e) => self.ty_to_string(e), + token::NtPath(ref e) => self.path_to_string(e), + token::NtItem(ref e) => self.item_to_string(e), + token::NtBlock(ref e) => self.block_to_string(e), + token::NtStmt(ref e) => self.stmt_to_string(e), + token::NtPat(ref e) => self.pat_to_string(e), + token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw).to_string(), + token::NtLifetime(e) => e.to_string(), + token::NtLiteral(ref e) => self.expr_to_string(e), + token::NtTT(ref tree) => self.tt_to_string(tree), + token::NtVis(ref e) => self.vis_to_string(e), + } + } + + /// Print the token kind precisely, without converting `$crate` into its respective crate name. + fn token_kind_to_string(&self, tok: &TokenKind) -> String { + self.token_kind_to_string_ext(tok, None) + } + + fn token_kind_to_string_ext( + &self, + tok: &TokenKind, + convert_dollar_crate: Option<Span>, + ) -> String { + match *tok { + token::Eq => "=".to_string(), + token::Lt => "<".to_string(), + token::Le => "<=".to_string(), + token::EqEq => "==".to_string(), + token::Ne => "!=".to_string(), + token::Ge => ">=".to_string(), + token::Gt => ">".to_string(), + token::Not => "!".to_string(), + token::Tilde => "~".to_string(), + token::OrOr => "||".to_string(), + token::AndAnd => "&&".to_string(), + token::BinOp(op) => binop_to_string(op).to_string(), + token::BinOpEq(op) => format!("{}=", binop_to_string(op)), + + /* Structural symbols */ + token::At => "@".to_string(), + token::Dot => ".".to_string(), + token::DotDot => "..".to_string(), + token::DotDotDot => "...".to_string(), + token::DotDotEq => "..=".to_string(), + token::Comma => ",".to_string(), + token::Semi => ";".to_string(), + token::Colon => ":".to_string(), + token::ModSep => "::".to_string(), + token::RArrow => "->".to_string(), + token::LArrow => "<-".to_string(), + token::FatArrow => "=>".to_string(), + token::OpenDelim(token::Paren) => "(".to_string(), + token::CloseDelim(token::Paren) => ")".to_string(), + token::OpenDelim(token::Bracket) => "[".to_string(), + token::CloseDelim(token::Bracket) => "]".to_string(), + token::OpenDelim(token::Brace) => "{".to_string(), + token::CloseDelim(token::Brace) => "}".to_string(), + token::OpenDelim(token::NoDelim) | token::CloseDelim(token::NoDelim) => "".to_string(), + token::Pound => "#".to_string(), + token::Dollar => "$".to_string(), + token::Question => "?".to_string(), + token::SingleQuote => "'".to_string(), + + /* Literals */ + token::Literal(lit) => literal_to_string(lit), + + /* Name components */ + token::Ident(s, is_raw) => { + IdentPrinter::new(s, is_raw, convert_dollar_crate).to_string() + } + token::Lifetime(s) => s.to_string(), + + /* Other */ + token::DocComment(comment_kind, attr_style, data) => { + doc_comment_to_string(comment_kind, attr_style, data) + } + token::Eof => "<eof>".to_string(), + + token::Interpolated(ref nt) => self.nonterminal_to_string(nt), + } + } + + /// Print the token precisely, without converting `$crate` into its respective crate name. + fn token_to_string(&self, token: &Token) -> String { + self.token_to_string_ext(token, false) + } + + fn token_to_string_ext(&self, token: &Token, convert_dollar_crate: bool) -> String { + let convert_dollar_crate = convert_dollar_crate.then_some(token.span); + self.token_kind_to_string_ext(&token.kind, convert_dollar_crate) + } + + fn ty_to_string(&self, ty: &ast::Ty) -> String { + self.to_string(|s| s.print_type(ty)) + } + + fn bounds_to_string(&self, bounds: &[ast::GenericBound]) -> String { + self.to_string(|s| s.print_type_bounds("", bounds)) + } + + fn pat_to_string(&self, pat: &ast::Pat) -> String { + self.to_string(|s| s.print_pat(pat)) + } + + fn expr_to_string(&self, e: &ast::Expr) -> String { + self.to_string(|s| s.print_expr(e)) + } + + fn tt_to_string(&self, tt: &TokenTree) -> String { + self.to_string(|s| s.print_tt(tt, false)) + } + + fn tts_to_string(&self, tokens: &TokenStream) -> String { + self.to_string(|s| s.print_tts(tokens, false)) + } + + fn stmt_to_string(&self, stmt: &ast::Stmt) -> String { + self.to_string(|s| s.print_stmt(stmt)) + } + + fn item_to_string(&self, i: &ast::Item) -> String { + self.to_string(|s| s.print_item(i)) + } + + fn generic_params_to_string(&self, generic_params: &[ast::GenericParam]) -> String { + self.to_string(|s| s.print_generic_params(generic_params)) + } + + fn path_to_string(&self, p: &ast::Path) -> String { + self.to_string(|s| s.print_path(p, false, 0)) + } + + fn path_segment_to_string(&self, p: &ast::PathSegment) -> String { + self.to_string(|s| s.print_path_segment(p, false)) + } + + fn vis_to_string(&self, v: &ast::Visibility) -> String { + self.to_string(|s| s.print_visibility(v)) + } + + fn block_to_string(&self, blk: &ast::Block) -> String { + self.to_string(|s| { + // Containing cbox, will be closed by `print_block` at `}`. + s.cbox(INDENT_UNIT); + // Head-ibox, will be closed by `print_block` after `{`. + s.ibox(0); + s.print_block(blk) + }) + } + + fn meta_list_item_to_string(&self, li: &ast::NestedMetaItem) -> String { + self.to_string(|s| s.print_meta_list_item(li)) + } + + fn attr_item_to_string(&self, ai: &ast::AttrItem) -> String { + self.to_string(|s| s.print_attr_item(ai, ai.path.span)) + } + + fn attribute_to_string(&self, attr: &ast::Attribute) -> String { + self.to_string(|s| s.print_attribute(attr)) + } + + fn param_to_string(&self, arg: &ast::Param) -> String { + self.to_string(|s| s.print_param(arg, false)) + } + + fn to_string(&self, f: impl FnOnce(&mut State<'_>)) -> String { + let mut printer = State::new(); + printer.insert_extra_parens = self.insert_extra_parens(); + f(&mut printer); + printer.s.eof() + } } impl<'a> PrintState<'a> for State<'a> { + fn insert_extra_parens(&self) -> bool { + self.insert_extra_parens + } fn comments(&mut self) -> &mut Option<Comments<'a>> { &mut self.comments } @@ -856,6 +878,20 @@ impl<'a> PrintState<'a> for State<'a> { } impl<'a> State<'a> { + pub fn new() -> State<'a> { + State { + s: pp::mk_printer(), + comments: None, + ann: &NoAnn, + is_expanded: false, + insert_extra_parens: true, + } + } + + pub(super) fn without_insert_extra_parens() -> State<'a> { + State { insert_extra_parens: false, ..State::new() } + } + // Synthesizes a comment that was not textually present in the original source // file. pub fn synth_comment(&mut self, text: String) { @@ -1139,7 +1175,7 @@ impl<'a> State<'a> { self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs); } ast::ItemKind::Mod(ref _mod) => { - self.head(to_string(|s| { + self.head(self.to_string(|s| { s.print_visibility(&item.vis); s.print_unsafety(_mod.unsafety); s.word("mod"); @@ -1158,7 +1194,7 @@ impl<'a> State<'a> { } } ast::ItemKind::ForeignMod(ref nmod) => { - self.head(to_string(|s| { + self.head(self.to_string(|s| { s.print_unsafety(nmod.unsafety); s.word("extern"); })); @@ -1366,7 +1402,7 @@ impl<'a> State<'a> { ast::CrateSugar::JustCrate => self.word_nbsp("crate"), }, ast::VisibilityKind::Restricted { ref path, .. } => { - let path = to_string(|s| s.print_path(path, false, 0)); + let path = self.to_string(|s| s.print_path(path, false, 0)); if path == "self" || path == "super" { self.word_nbsp(format!("pub({})", path)) } else { @@ -1658,7 +1694,8 @@ impl<'a> State<'a> { } /// Prints `expr` or `(expr)` when `needs_par` holds. - fn print_expr_cond_paren(&mut self, expr: &ast::Expr, needs_par: bool) { + fn print_expr_cond_paren(&mut self, expr: &ast::Expr, mut needs_par: bool) { + needs_par &= self.insert_extra_parens; if needs_par { self.popen(); } diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 325af56f3cd..9c309345000 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -154,7 +154,7 @@ pub struct ConstStability { } /// The available stability levels. -#[derive(Encodable, Decodable, PartialEq, PartialOrd, Copy, Clone, Debug, Eq, Hash)] +#[derive(Encodable, Decodable, PartialEq, Copy, Clone, Debug, Eq, Hash)] #[derive(HashStable_Generic)] pub enum StabilityLevel { // Reason for the current stability level and the relevant rust-lang issue diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index f4924997d1a..2e52d2a3923 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1137,12 +1137,9 @@ impl<'a> MethodDef<'a> { /// for each of the self-args, carried in precomputed variables. /// ```{.text} - /// let __self0_vi = unsafe { - /// std::intrinsics::discriminant_value(&self) }; - /// let __self1_vi = unsafe { - /// std::intrinsics::discriminant_value(&arg1) }; - /// let __self2_vi = unsafe { - /// std::intrinsics::discriminant_value(&arg2) }; + /// let __self0_vi = std::intrinsics::discriminant_value(&self); + /// let __self1_vi = std::intrinsics::discriminant_value(&arg1); + /// let __self2_vi = std::intrinsics::discriminant_value(&arg2); /// /// if __self0_vi == __self1_vi && __self0_vi == __self2_vi && ... { /// match (...) { @@ -1325,7 +1322,7 @@ impl<'a> MethodDef<'a> { // Since we know that all the arguments will match if we reach // the match expression we add the unreachable intrinsics as the // result of the catch all which should help llvm in optimizing it - Some(deriving::call_intrinsic(cx, sp, sym::unreachable, vec![])) + Some(deriving::call_unreachable(cx, sp)) } _ => None, }; @@ -1356,12 +1353,9 @@ impl<'a> MethodDef<'a> { // with three Self args, builds three statements: // // ``` - // let __self0_vi = unsafe { - // std::intrinsics::discriminant_value(&self) }; - // let __self1_vi = unsafe { - // std::intrinsics::discriminant_value(&arg1) }; - // let __self2_vi = unsafe { - // std::intrinsics::discriminant_value(&arg2) }; + // let __self0_vi = std::intrinsics::discriminant_value(&self); + // let __self1_vi = std::intrinsics::discriminant_value(&arg1); + // let __self2_vi = std::intrinsics::discriminant_value(&arg2); // ``` let mut index_let_stmts: Vec<ast::Stmt> = Vec::with_capacity(vi_idents.len() + 1); @@ -1474,7 +1468,7 @@ impl<'a> MethodDef<'a> { // derive Debug on such a type could here generate code // that needs the feature gate enabled.) - deriving::call_intrinsic(cx, sp, sym::unreachable, vec![]) + deriving::call_unreachable(cx, sp) } else { // Final wrinkle: the self_args are expressions that deref // down to desired places, but we cannot actually deref diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs index 9c8e0fc2f01..bf950934928 100644 --- a/compiler/rustc_builtin_macros/src/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -68,7 +68,14 @@ fn call_intrinsic( ) -> P<ast::Expr> { let span = cx.with_def_site_ctxt(span); let path = cx.std_path(&[sym::intrinsics, intrinsic]); - let call = cx.expr_call_global(span, path, args); + cx.expr_call_global(span, path, args) +} + +/// Constructs an expression that calls the `unreachable` intrinsic. +fn call_unreachable(cx: &ExtCtxt<'_>, span: Span) -> P<ast::Expr> { + let span = cx.with_def_site_ctxt(span); + let path = cx.std_path(&[sym::intrinsics, sym::unreachable]); + let call = cx.expr_call_global(span, path, vec![]); cx.expr_block(P(ast::Block { stmts: vec![cx.stmt_expr(call)], diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index ff81b5eca13..b69b00d65f2 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -385,7 +385,7 @@ pub mod printf { if let Start = state { match c { '1'..='9' => { - let end = at_next_cp_while(next, is_digit); + let end = at_next_cp_while(next, char::is_ascii_digit); match end.next_cp() { // Yes, this *is* the parameter. Some(('$', end2)) => { @@ -427,7 +427,7 @@ pub mod printf { move_to!(next); } '1'..='9' => { - let end = at_next_cp_while(next, is_digit); + let end = at_next_cp_while(next, char::is_ascii_digit); state = Prec; width = Some(Num::from_str(at.slice_between(end).unwrap(), None)); move_to!(end); @@ -441,7 +441,7 @@ pub mod printf { } if let WidthArg = state { - let end = at_next_cp_while(at, is_digit); + let end = at_next_cp_while(at, char::is_ascii_digit); match end.next_cp() { Some(('$', end2)) => { state = Prec; @@ -473,7 +473,7 @@ pub mod printf { if let PrecInner = state { match c { '*' => { - let end = at_next_cp_while(next, is_digit); + let end = at_next_cp_while(next, char::is_ascii_digit); match end.next_cp() { Some(('$', end2)) => { state = Length; @@ -488,7 +488,7 @@ pub mod printf { } } '0'..='9' => { - let end = at_next_cp_while(next, is_digit); + let end = at_next_cp_while(next, char::is_ascii_digit); state = Length; precision = Some(Num::from_str(at.slice_between(end).unwrap(), None)); move_to!(end); @@ -563,12 +563,12 @@ pub mod printf { fn at_next_cp_while<F>(mut cur: Cur<'_>, mut pred: F) -> Cur<'_> where - F: FnMut(char) -> bool, + F: FnMut(&char) -> bool, { loop { match cur.next_cp() { Some((c, next)) => { - if pred(c) { + if pred(&c) { cur = next; } else { return cur; @@ -579,14 +579,7 @@ pub mod printf { } } - fn is_digit(c: char) -> bool { - match c { - '0'..='9' => true, - _ => false, - } - } - - fn is_flag(c: char) -> bool { + fn is_flag(c: &char) -> bool { match c { '0' | '-' | '+' | ' ' | '#' | '\'' => true, _ => false, @@ -723,17 +716,11 @@ pub mod shell { } fn is_ident_head(c: char) -> bool { - match c { - 'a'..='z' | 'A'..='Z' | '_' => true, - _ => false, - } + c.is_ascii_alphabetic() || c == '_' } fn is_ident_tail(c: char) -> bool { - match c { - '0'..='9' => true, - c => is_ident_head(c), - } + c.is_ascii_alphanumeric() || c == '_' } #[cfg(test)] diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 0a60ca8faaa..da74f0aeaa1 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -37,7 +37,7 @@ struct TestCtxt<'a> { pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) { let span_diagnostic = sess.diagnostic(); let panic_strategy = sess.panic_strategy(); - let platform_panic_strategy = sess.target.target.options.panic_strategy; + let platform_panic_strategy = sess.target.options.panic_strategy; // Check for #![reexport_test_harness_main = "some_name"] which gives the // main test function the name `some_name` without hygiene. This needs to be diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs index e028b2c2dc7..d02bc41f4af 100644 --- a/compiler/rustc_codegen_llvm/src/allocator.rs +++ b/compiler/rustc_codegen_llvm/src/allocator.rs @@ -16,10 +16,10 @@ pub(crate) unsafe fn codegen( ) { let llcx = &*mods.llcx; let llmod = mods.llmod(); - let usize = match &tcx.sess.target.target.target_pointer_width[..] { - "16" => llvm::LLVMInt16TypeInContext(llcx), - "32" => llvm::LLVMInt32TypeInContext(llcx), - "64" => llvm::LLVMInt64TypeInContext(llcx), + let usize = match tcx.sess.target.pointer_width { + 16 => llvm::LLVMInt16TypeInContext(llcx), + 32 => llvm::LLVMInt32TypeInContext(llcx), + 64 => llvm::LLVMInt64TypeInContext(llcx), tws => bug!("Unsupported target word size for int: {}", tws), }; let i8 = llvm::LLVMInt8TypeInContext(llcx); @@ -57,7 +57,7 @@ pub(crate) unsafe fn codegen( let name = format!("__rust_{}", method.name); let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty); - if tcx.sess.target.target.options.default_hidden_visibility { + if tcx.sess.target.options.default_hidden_visibility { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } if tcx.sess.must_emit_unwind_tables() { @@ -98,7 +98,7 @@ pub(crate) unsafe fn codegen( // -> ! DIFlagNoReturn llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn); - if tcx.sess.target.target.options.default_hidden_visibility { + if tcx.sess.target.options.default_hidden_visibility { llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } if tcx.sess.must_emit_unwind_tables() { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index f801f845ac1..b096664bc74 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -60,7 +60,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { // Default per-arch clobbers // Basically what clang does - let arch_clobbers = match &self.sess().target.target.arch[..] { + let arch_clobbers = match &self.sess().target.arch[..] { "x86" | "x86_64" => vec!["~{dirflag}", "~{fpsr}", "~{flags}"], "mips" | "mips64" => vec!["~{$1}"], _ => Vec::new(), @@ -259,7 +259,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {} InlineAsmArch::Nvptx64 => {} InlineAsmArch::Hexagon => {} - InlineAsmArch::Mips => {} + InlineAsmArch::Mips | InlineAsmArch::Mips64 => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -710,6 +710,7 @@ fn llvm_fixup_input( // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()), + Primitive::F64 => bx.bitcast(value, bx.cx.type_i64()), _ => value, }, _ => value, @@ -785,6 +786,7 @@ fn llvm_fixup_output( Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()), Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()), + Primitive::F64 => bx.bitcast(value, bx.cx.type_f64()), _ => value, }, _ => value, @@ -854,6 +856,7 @@ fn llvm_fixup_output_type( // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), Primitive::F32 => cx.type_i32(), + Primitive::F64 => cx.type_i64(), _ => layout.llvm_type(cx), }, _ => layout.llvm_type(cx), diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index f02c30c3ee3..2075c2e1911 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -6,7 +6,7 @@ use rustc_codegen_ssa::traits::*; use rustc_data_structures::const_cstr; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::small_c_str::SmallCStr; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; +use rustc_hir::def_id::DefId; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::query::Providers; @@ -31,7 +31,7 @@ fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) { Hint => Attribute::InlineHint.apply_llfn(Function, val), Always => Attribute::AlwaysInline.apply_llfn(Function, val), Never => { - if cx.tcx().sess.target.target.arch != "amdgpu" { + if cx.tcx().sess.target.arch != "amdgpu" { Attribute::NoInline.apply_llfn(Function, val); } } @@ -91,8 +91,7 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // The function name varies on platforms. // See test/CodeGen/mcount.c in clang. let mcount_name = - CString::new(cx.sess().target.target.options.target_mcount.as_str().as_bytes()) - .unwrap(); + CString::new(cx.sess().target.options.target_mcount.as_str().as_bytes()).unwrap(); llvm::AddFunctionAttrStringValue( llfn, @@ -106,7 +105,7 @@ fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { // Only use stack probes if the target specification indicates that we // should be using stack probes - if !cx.sess().target.target.options.stack_probes { + if !cx.sess().target.options.stack_probes { return; } @@ -175,7 +174,6 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator<Item = &str> { .split(',') .filter(|f| !RUSTC_SPECIFIC_FEATURES.iter().any(|s| f.contains(s))); sess.target - .target .options .features .split(',') @@ -194,6 +192,18 @@ pub fn apply_target_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { ); } +pub fn apply_tune_cpu_attr(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) { + if let Some(tune) = llvm_util::tune_cpu(cx.tcx.sess) { + let tune_cpu = SmallCStr::new(tune); + llvm::AddFunctionAttrStringValue( + llfn, + llvm::AttributePlace::Function, + const_cstr!("tune-cpu"), + tune_cpu.as_c_str(), + ); + } +} + /// Sets the `NonLazyBind` LLVM attribute on a given function, /// assuming the codegen options allow skipping the PLT. pub fn non_lazy_bind(sess: &Session, llfn: &'ll Value) { @@ -303,6 +313,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: // Without this, ThinLTO won't inline Rust functions into Clang generated // functions (because Clang annotates functions this way too). apply_target_cpu_attr(cx, llfn); + // tune-cpu is only conveyed through the attribute for our purpose. + // The target doesn't care; the subtarget reads our attribute. + apply_tune_cpu_attr(cx, llfn); let features = llvm_target_features(cx.tcx.sess) .map(|s| s.to_string()) @@ -330,7 +343,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: // Note that currently the `wasm-import-module` doesn't do anything, but // eventually LLVM 7 should read this and ferry the appropriate import // module to the output file. - if cx.tcx.sess.target.target.arch == "wasm32" { + if cx.tcx.sess.target.arch == "wasm32" { if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) { llvm::AddFunctionAttrStringValue( llfn, @@ -352,23 +365,7 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: } } -pub fn provide(providers: &mut Providers) { - use rustc_codegen_ssa::target_features::{all_known_features, supported_target_features}; - providers.supported_target_features = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - if tcx.sess.opts.actually_rustdoc { - // rustdoc needs to be able to document functions that use all the features, so - // provide them all. - all_known_features().map(|(a, b)| (a.to_string(), b)).collect() - } else { - supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect() - } - }; - - provide_extern(providers); -} - -pub fn provide_extern(providers: &mut Providers) { +pub fn provide_both(providers: &mut Providers) { providers.wasm_import_module_map = |tcx, cnum| { // Build up a map from DefId to a `NativeLib` structure, where // `NativeLib` internally contains information about diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs index a115a1e9516..595655b2ca2 100644 --- a/compiler/rustc_codegen_llvm/src/back/archive.rs +++ b/compiler/rustc_codegen_llvm/src/back/archive.rs @@ -206,7 +206,7 @@ impl<'a> LlvmArchiveBuilder<'a> { } fn llvm_archive_kind(&self) -> Result<ArchiveKind, &str> { - let kind = &*self.config.sess.target.target.options.archive_format; + let kind = &*self.config.sess.target.options.archive_format; kind.parse().map_err(|_| kind) } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 4b2d5907a02..ff312bade25 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -2,14 +2,14 @@ use crate::back::write::{ self, save_temp_bitcode, to_llvm_opt_settings, with_llvm_pmb, DiagnosticHandlers, }; use crate::llvm::archive_ro::ArchiveRO; -use crate::llvm::{self, False, True}; +use crate::llvm::{self, build_string, False, True}; use crate::{LlvmCodegenBackend, ModuleLlvm}; use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule, ThinShared}; use rustc_codegen_ssa::back::symbol_export; use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{FatalError, Handler}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; @@ -22,16 +22,14 @@ use tracing::{debug, info}; use std::ffi::{CStr, CString}; use std::fs::File; use std::io; -use std::mem; use std::path::Path; use std::ptr; use std::slice; use std::sync::Arc; -/// We keep track of past LTO imports that were used to produce the current set -/// of compiled object files that we might choose to reuse during this -/// compilation session. -pub const THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-imports.bin"; +/// We keep track of the computed LTO cache keys from the previous +/// session to determine which CGUs we can reuse. +pub const THIN_LTO_KEYS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-keys.bin"; pub fn crate_type_allows_lto(crate_type: CrateType) -> bool { match crate_type { @@ -485,31 +483,31 @@ fn thin_lto( ) .ok_or_else(|| write::llvm_err(&diag_handler, "failed to prepare thin LTO context"))?; - info!("thin LTO data created"); + let data = ThinData(data); - let (import_map_path, prev_import_map, curr_import_map) = - if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir { - let path = incr_comp_session_dir.join(THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME); - // If previous imports have been deleted, or we get an IO error - // reading the file storing them, then we'll just use `None` as the - // prev_import_map, which will force the code to be recompiled. - let prev = if path.exists() { - ThinLTOImportMaps::load_from_file(&path).ok() - } else { - None - }; - let curr = ThinLTOImportMaps::from_thin_lto_data(data); - (Some(path), prev, curr) - } else { - // If we don't compile incrementally, we don't need to load the - // import data from LLVM. - assert!(green_modules.is_empty()); - let curr = ThinLTOImportMaps::default(); - (None, None, curr) - }; - info!("thin LTO import map loaded"); + info!("thin LTO data created"); - let data = ThinData(data); + let (key_map_path, prev_key_map, curr_key_map) = if let Some(ref incr_comp_session_dir) = + cgcx.incr_comp_session_dir + { + let path = incr_comp_session_dir.join(THIN_LTO_KEYS_INCR_COMP_FILE_NAME); + // If the previous file was deleted, or we get an IO error + // reading the file, then we'll just use `None` as the + // prev_key_map, which will force the code to be recompiled. + let prev = + if path.exists() { ThinLTOKeysMap::load_from_file(&path).ok() } else { None }; + let curr = ThinLTOKeysMap::from_thin_lto_modules(&data, &thin_modules, &module_names); + (Some(path), prev, curr) + } else { + // If we don't compile incrementally, we don't need to load the + // import data from LLVM. + assert!(green_modules.is_empty()); + let curr = ThinLTOKeysMap::default(); + (None, None, curr) + }; + info!("thin LTO cache key map loaded"); + info!("prev_key_map: {:#?}", prev_key_map); + info!("curr_key_map: {:#?}", curr_key_map); // Throw our data in an `Arc` as we'll be sharing it across threads. We // also put all memory referenced by the C++ data (buffers, ids, etc) @@ -528,60 +526,14 @@ fn thin_lto( info!("checking which modules can be-reused and which have to be re-optimized."); for (module_index, module_name) in shared.module_names.iter().enumerate() { let module_name = module_name_to_str(module_name); - - // If (1.) the module hasn't changed, and (2.) none of the modules - // it imports from have changed, *and* (3.) the import and export - // sets themselves have not changed from the previous compile when - // it was last ThinLTO'ed, then we can re-use the post-ThinLTO - // version of the module. Otherwise, freshly perform LTO - // optimization. - // - // (Note that globally, the export set is just the inverse of the - // import set.) - // - // For further justification of why the above is necessary and sufficient, - // see the LLVM blog post on ThinLTO: - // - // http://blog.llvm.org/2016/06/thinlto-scalable-and-incremental-lto.html - // - // which states the following: - // - // ```quote - // any particular ThinLTO backend must be redone iff: - // - // 1. The corresponding (primary) module’s bitcode changed - // 2. The list of imports into or exports from the module changed - // 3. The bitcode for any module being imported from has changed - // 4. Any global analysis result affecting either the primary module - // or anything it imports has changed. - // ``` - // - // This strategy means we can always save the computed imports as - // canon: when we reuse the post-ThinLTO version, condition (3.) - // ensures that the current import set is the same as the previous - // one. (And of course, when we don't reuse the post-ThinLTO - // version, the current import set *is* the correct one, since we - // are doing the ThinLTO in this current compilation cycle.) - // - // For more discussion, see rust-lang/rust#59535 (where the import - // issue was discovered) and rust-lang/rust#69798 (where the - // analogous export issue was discovered). - if let (Some(prev_import_map), true) = - (prev_import_map.as_ref(), green_modules.contains_key(module_name)) + if let (Some(prev_key_map), true) = + (prev_key_map.as_ref(), green_modules.contains_key(module_name)) { assert!(cgcx.incr_comp_session_dir.is_some()); - let prev_imports = prev_import_map.imports_of(module_name); - let curr_imports = curr_import_map.imports_of(module_name); - let prev_exports = prev_import_map.exports_of(module_name); - let curr_exports = curr_import_map.exports_of(module_name); - let imports_all_green = curr_imports - .iter() - .all(|imported_module| green_modules.contains_key(imported_module)); - if imports_all_green - && equivalent_as_sets(prev_imports, curr_imports) - && equivalent_as_sets(prev_exports, curr_exports) - { + // If a module exists in both the current and the previous session, + // and has the same LTO cache key in both sessions, then we can re-use it + if prev_key_map.keys.get(module_name) == curr_key_map.keys.get(module_name) { let work_product = green_modules[module_name].clone(); copy_jobs.push(work_product); info!(" - {}: re-used", module_name); @@ -599,10 +551,10 @@ fn thin_lto( } // Save the current ThinLTO import information for the next compilation - // session, overwriting the previous serialized imports (if any). - if let Some(path) = import_map_path { - if let Err(err) = curr_import_map.save_to_file(&path) { - let msg = format!("Error while writing ThinLTO import data: {}", err); + // session, overwriting the previous serialized data (if any). + if let Some(path) = key_map_path { + if let Err(err) = curr_key_map.save_to_file(&path) { + let msg = format!("Error while writing ThinLTO key data: {}", err); return Err(write::llvm_err(&diag_handler, &msg)); } } @@ -611,24 +563,6 @@ fn thin_lto( } } -/// Given two slices, each with no repeat elements. returns true if and only if -/// the two slices have the same contents when considered as sets (i.e. when -/// element order is disregarded). -fn equivalent_as_sets(a: &[String], b: &[String]) -> bool { - // cheap path: unequal lengths means cannot possibly be set equivalent. - if a.len() != b.len() { - return false; - } - // fast path: before building new things, check if inputs are equivalent as is. - if a == b { - return true; - } - // slow path: general set comparison. - let a: FxHashSet<&str> = a.iter().map(|s| s.as_str()).collect(); - let b: FxHashSet<&str> = b.iter().map(|s| s.as_str()).collect(); - a == b -} - pub(crate) fn run_pass_manager( cgcx: &CodegenContext<LlvmCodegenBackend>, module: &ModuleCodegen<ModuleLlvm>, @@ -942,113 +876,56 @@ pub unsafe fn optimize_thin_module( Ok(module) } -/// Summarizes module import/export relationships used by LLVM's ThinLTO pass. -/// -/// Note that we tend to have two such instances of `ThinLTOImportMaps` in use: -/// one loaded from a file that represents the relationships used during the -/// compilation associated with the incremetnal build artifacts we are -/// attempting to reuse, and another constructed via `from_thin_lto_data`, which -/// captures the relationships of ThinLTO in the current compilation. +/// Maps LLVM module identifiers to their corresponding LLVM LTO cache keys #[derive(Debug, Default)] -pub struct ThinLTOImportMaps { - // key = llvm name of importing module, value = list of modules it imports from - imports: FxHashMap<String, Vec<String>>, - // key = llvm name of exporting module, value = list of modules it exports to - exports: FxHashMap<String, Vec<String>>, +pub struct ThinLTOKeysMap { + // key = llvm name of importing module, value = LLVM cache key + keys: FxHashMap<String, String>, } -impl ThinLTOImportMaps { - /// Returns modules imported by `llvm_module_name` during some ThinLTO pass. - fn imports_of(&self, llvm_module_name: &str) -> &[String] { - self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[]) - } - - /// Returns modules exported by `llvm_module_name` during some ThinLTO pass. - fn exports_of(&self, llvm_module_name: &str) -> &[String] { - self.exports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[]) - } - +impl ThinLTOKeysMap { fn save_to_file(&self, path: &Path) -> io::Result<()> { use std::io::Write; let file = File::create(path)?; let mut writer = io::BufWriter::new(file); - for (importing_module_name, imported_modules) in &self.imports { - writeln!(writer, "{}", importing_module_name)?; - for imported_module in imported_modules { - writeln!(writer, " {}", imported_module)?; - } - writeln!(writer)?; + for (module, key) in &self.keys { + writeln!(writer, "{} {}", module, key)?; } Ok(()) } - fn load_from_file(path: &Path) -> io::Result<ThinLTOImportMaps> { + fn load_from_file(path: &Path) -> io::Result<Self> { use std::io::BufRead; - let mut imports = FxHashMap::default(); - let mut exports: FxHashMap<_, Vec<_>> = FxHashMap::default(); - let mut current_module: Option<String> = None; - let mut current_imports: Vec<String> = vec![]; + let mut keys = FxHashMap::default(); let file = File::open(path)?; for line in io::BufReader::new(file).lines() { let line = line?; - if line.is_empty() { - let importing_module = current_module.take().expect("Importing module not set"); - for imported in ¤t_imports { - exports.entry(imported.clone()).or_default().push(importing_module.clone()); - } - imports.insert(importing_module, mem::replace(&mut current_imports, vec![])); - } else if line.starts_with(' ') { - // Space marks an imported module - assert_ne!(current_module, None); - current_imports.push(line.trim().to_string()); - } else { - // Otherwise, beginning of a new module (must be start or follow empty line) - assert_eq!(current_module, None); - current_module = Some(line.trim().to_string()); - } + let mut split = line.split(" "); + let module = split.next().unwrap(); + let key = split.next().unwrap(); + assert_eq!(split.next(), None, "Expected two space-separated values, found {:?}", line); + keys.insert(module.to_string(), key.to_string()); } - Ok(ThinLTOImportMaps { imports, exports }) + Ok(Self { keys }) } - /// Loads the ThinLTO import map from ThinLTOData. - unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImportMaps { - unsafe extern "C" fn imported_module_callback( - payload: *mut libc::c_void, - importing_module_name: *const libc::c_char, - imported_module_name: *const libc::c_char, - ) { - let map = &mut *(payload as *mut ThinLTOImportMaps); - let importing_module_name = CStr::from_ptr(importing_module_name); - let importing_module_name = module_name_to_str(&importing_module_name); - let imported_module_name = CStr::from_ptr(imported_module_name); - let imported_module_name = module_name_to_str(&imported_module_name); - - if !map.imports.contains_key(importing_module_name) { - map.imports.insert(importing_module_name.to_owned(), vec![]); - } - - map.imports - .get_mut(importing_module_name) - .unwrap() - .push(imported_module_name.to_owned()); - - if !map.exports.contains_key(imported_module_name) { - map.exports.insert(imported_module_name.to_owned(), vec![]); - } - - map.exports - .get_mut(imported_module_name) - .unwrap() - .push(importing_module_name.to_owned()); - } - - let mut map = ThinLTOImportMaps::default(); - llvm::LLVMRustGetThinLTOModuleImports( - data, - imported_module_callback, - &mut map as *mut _ as *mut libc::c_void, - ); - map + fn from_thin_lto_modules( + data: &ThinData, + modules: &[llvm::ThinLTOModule], + names: &[CString], + ) -> Self { + let keys = modules + .iter() + .zip(names.iter()) + .map(|(module, name)| { + let key = build_string(|rust_str| unsafe { + llvm::LLVMRustComputeLTOCacheKey(rust_str, module.identifier, data.0); + }) + .expect("Invalid ThinLTO module key"); + (name.clone().into_string().unwrap(), key) + }) + .collect(); + Self { keys } } } diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index f35c1016f86..ea1a7cfa5d3 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -128,40 +128,40 @@ pub fn target_machine_factory( let (opt_level, _) = to_llvm_opt_settings(optlvl); let use_softfp = sess.opts.cg.soft_float; - let ffunction_sections = sess.target.target.options.function_sections; + let ffunction_sections = sess.target.options.function_sections; let fdata_sections = ffunction_sections; let code_model = to_llvm_code_model(sess.code_model()); let features = attributes::llvm_target_features(sess).collect::<Vec<_>>(); - let mut singlethread = sess.target.target.options.singlethread; + let mut singlethread = sess.target.options.singlethread; // On the wasm target once the `atomics` feature is enabled that means that // we're no longer single-threaded, or otherwise we don't want LLVM to // lower atomic operations to single-threaded operations. if singlethread - && sess.target.target.llvm_target.contains("wasm32") + && sess.target.llvm_target.contains("wasm32") && sess.target_features.contains(&sym::atomics) { singlethread = false; } - let triple = SmallCStr::new(&sess.target.target.llvm_target); + let triple = SmallCStr::new(&sess.target.llvm_target); let cpu = SmallCStr::new(llvm_util::target_cpu(sess)); let features = features.join(","); let features = CString::new(features).unwrap(); - let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname); - let trap_unreachable = sess.target.target.options.trap_unreachable; + let abi = SmallCStr::new(&sess.target.options.llvm_abiname); + let trap_unreachable = sess.target.options.trap_unreachable; let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; let asm_comments = sess.asm_comments(); - let relax_elf_relocations = sess.target.target.options.relax_elf_relocations; + let relax_elf_relocations = sess.target.options.relax_elf_relocations; let use_init_array = !sess .opts .debugging_opts .use_ctors_section - .unwrap_or(sess.target.target.options.use_ctors_section); + .unwrap_or(sess.target.options.use_ctors_section); Arc::new(move || { let tm = unsafe { diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index f35708b1d09..1090d4a25c7 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -60,7 +60,7 @@ pub fn write_compressed_metadata<'tcx>( unsafe { llvm::LLVMAddGlobal(metadata_llmod, common::val_ty(llconst), buf.as_ptr()) }; unsafe { llvm::LLVMSetInitializer(llglobal, llconst); - let section_name = metadata::metadata_section_name(&tcx.sess.target.target); + let section_name = metadata::metadata_section_name(&tcx.sess.target); let name = SmallCStr::new(section_name); llvm::LLVMSetSection(llglobal, name.as_ptr()); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index f496f3283da..174620ea2fa 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -308,8 +308,8 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { use rustc_middle::ty::{Int, Uint}; let new_kind = match ty.kind() { - Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.ptr_width)), - Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.ptr_width)), + Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)), + Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)), t @ (Uint(_) | Int(_)) => t.clone(), _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), }; @@ -541,7 +541,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } fn range_metadata(&mut self, load: &'ll Value, range: Range<u128>) { - if self.sess().target.target.arch == "amdgpu" { + if self.sess().target.arch == "amdgpu" { // amdgpu/LLVM does something weird and thinks a i64 value is // split into a v2i32, halving the bitwidth LLVM expects, // tripping an assertion. So, for now, just disable this @@ -671,7 +671,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // WebAssembly has saturating floating point to integer casts if the // `nontrapping-fptoint` target feature is activated. We'll use those if // they are available. - if self.sess().target.target.arch == "wasm32" + if self.sess().target.arch == "wasm32" && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) { let src_ty = self.cx.val_ty(val); @@ -696,7 +696,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { // WebAssembly has saturating floating point to integer casts if the // `nontrapping-fptoint` target feature is activated. We'll use those if // they are available. - if self.sess().target.target.arch == "wasm32" + if self.sess().target.arch == "wasm32" && self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) { let src_ty = self.cx.val_ty(val); @@ -1427,7 +1427,7 @@ impl Builder<'a, 'll, 'tcx> { } fn wasm_and_missing_nontrapping_fptoint(&self) -> bool { - self.sess().target.target.arch == "wasm32" + self.sess().target.arch == "wasm32" && !self.sess().target_features.contains(&sym::nontrapping_dash_fptoint) } } diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index 4afd906fce7..e2003472d12 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -176,7 +176,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value // should use dllimport for functions. if cx.use_dll_storage_attrs && tcx.is_dllimport_foreign_item(instance_def_id) - && tcx.sess.target.target.target_env != "gnu" + && tcx.sess.target.target_env != "gnu" { unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 6d3582d3027..b57a23328b6 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -92,7 +92,7 @@ fn set_global_alignment(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Alig // The target may require greater alignment for globals than the type does. // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, // which can force it to be smaller. Rust doesn't support this yet. - if let Some(min) = cx.sess().target.target.options.min_global_align { + if let Some(min) = cx.sess().target.options.min_global_align { match Align::from_bits(min) { Ok(min) => align = align.max(min), Err(err) => { @@ -283,7 +283,7 @@ impl CodegenCx<'ll, 'tcx> { // argument validation. debug_assert!( !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled() - && self.tcx.sess.target.target.options.is_like_windows + && self.tcx.sess.target.options.is_like_windows && self.tcx.sess.opts.cg.prefer_dynamic) ); @@ -437,7 +437,7 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { // will use load-unaligned instructions instead, and thus avoiding the crash. // // We could remove this hack whenever we decide to drop macOS 10.10 support. - if self.tcx.sess.target.target.options.is_like_osx { + if self.tcx.sess.target.options.is_like_osx { // The `inspect` method is okay here because we checked relocations, and // because we are doing this access to inspect the final interpreter state // (not as part of the interpreter execution). diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1696f35563d..150cedde7e8 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -118,18 +118,18 @@ pub unsafe fn create_module( let mod_name = SmallCStr::new(mod_name); let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); - let mut target_data_layout = sess.target.target.data_layout.clone(); + let mut target_data_layout = sess.target.data_layout.clone(); if llvm_util::get_major_version() < 9 { target_data_layout = strip_function_ptr_alignment(target_data_layout); } if llvm_util::get_major_version() < 10 { - if sess.target.target.arch == "x86" || sess.target.target.arch == "x86_64" { + if sess.target.arch == "x86" || sess.target.arch == "x86_64" { target_data_layout = strip_x86_address_spaces(target_data_layout); } } // Ensure the data-layout values hardcoded remain the defaults. - if sess.target.target.options.is_builtin { + if sess.target.options.is_builtin { let tm = crate::back::write::create_informational_target_machine(tcx.sess); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); llvm::LLVMRustDisposeTargetMachine(tm); @@ -160,7 +160,7 @@ pub unsafe fn create_module( bug!( "data-layout for builtin `{}` target, `{}`, \ differs from LLVM default, `{}`", - sess.target.target.llvm_target, + sess.target.llvm_target, target_data_layout, llvm_data_layout ); @@ -170,7 +170,7 @@ pub unsafe fn create_module( let data_layout = SmallCStr::new(&target_data_layout); llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); - let llvm_target = SmallCStr::new(&sess.target.target.llvm_target); + let llvm_target = SmallCStr::new(&sess.target.llvm_target); llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); if sess.relocation_model() == RelocModel::Pic { @@ -190,7 +190,7 @@ pub unsafe fn create_module( } // Control Flow Guard is currently only supported by the MSVC linker on Windows. - if sess.target.target.options.is_like_msvc { + if sess.target.options.is_like_msvc { match sess.opts.cg.control_flow_guard { CFGuard::Disabled => {} CFGuard::NoChecks => { @@ -265,7 +265,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { // linker will take care of everything. Fixing this problem will likely // require adding a few attributes to Rust itself (feature gated at the // start) and then strongly recommending static linkage on Windows! - let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_windows; + let use_dll_storage_attrs = tcx.sess.target.options.is_like_windows; let check_overflow = tcx.sess.overflow_checks(); @@ -417,7 +417,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { } fn apply_target_cpu_attr(&self, llfn: &'ll Value) { - attributes::apply_target_cpu_attr(self, llfn) + attributes::apply_target_cpu_attr(self, llfn); + attributes::apply_tune_cpu_attr(self, llfn); } fn create_used_variable(&self) { @@ -838,7 +839,7 @@ impl CodegenCx<'b, 'tcx> { return eh_catch_typeinfo; } let tcx = self.tcx; - assert!(self.sess().target.target.options.is_like_emscripten); + assert!(self.sess().target.options.is_like_emscripten); let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() { Some(def_id) => self.get_static(def_id), _ => { @@ -877,7 +878,7 @@ impl HasDataLayout for CodegenCx<'ll, 'tcx> { impl HasTargetSpec for CodegenCx<'ll, 'tcx> { fn target_spec(&self) -> &Target { - &self.tcx.sess.target.target + &self.tcx.sess.target } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index 29edd66049c..79721ff7e2d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -67,5 +67,5 @@ pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool { !omit_gdb_pretty_printer_section && cx.sess().opts.debuginfo != DebugInfo::None - && cx.sess().target.target.options.emit_debug_gdb_scripts + && cx.sess().target.options.emit_debug_gdb_scripts } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 987149cb4c2..5587e6ead1d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -874,7 +874,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { // When targeting MSVC, emit MSVC style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) - let msvc_like_names = cx.tcx.sess.target.target.options.is_like_msvc; + let msvc_like_names = cx.tcx.sess.target.options.is_like_msvc; let (name, encoding) = match t.kind() { ty::Never => ("!", DW_ATE_unsigned), @@ -985,7 +985,7 @@ pub fn compile_unit_metadata( // if multiple object files with the same `DW_AT_name` are linked together. // As a workaround we generate unique names for each object file. Those do // not correspond to an actual source file but that should be harmless. - if tcx.sess.target.target.options.is_like_osx { + if tcx.sess.target.options.is_like_osx { name_in_debuginfo.push("@"); name_in_debuginfo.push(codegen_unit_name); } @@ -1401,7 +1401,7 @@ fn prepare_union_metadata( /// on MSVC we have to use the fallback mode, because LLVM doesn't /// lower variant parts to PDB. fn use_enum_fallback(cx: &CodegenCx<'_, '_>) -> bool { - cx.sess().target.target.options.is_like_msvc + cx.sess().target.options.is_like_msvc } // FIXME(eddyb) maybe precompute this? Right now it's computed once diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 7cdd366175d..80e0e7bf2e0 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -120,14 +120,12 @@ pub fn finalize(cx: &CodegenCx<'_, '_>) { // for macOS to understand. For more info see #11352 // This can be overridden using --llvm-opts -dwarf-version,N. // Android has the same issue (#22398) - if cx.sess().target.target.options.is_like_osx - || cx.sess().target.target.options.is_like_android - { - llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), 2) + if let Some(version) = cx.sess().target.options.dwarf_version { + llvm::LLVMRustAddModuleFlag(cx.llmod, "Dwarf Version\0".as_ptr().cast(), version) } // Indicate that we want CodeView debug information on MSVC - if cx.sess().target.target.options.is_like_msvc { + if cx.sess().target.options.is_like_msvc { llvm::LLVMRustAddModuleFlag(cx.llmod, "CodeView\0".as_ptr().cast(), 1) } @@ -348,7 +346,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { }); // Arguments types - if cx.sess().target.target.options.is_like_msvc { + if cx.sess().target.options.is_like_msvc { // FIXME(#42800): // There is a bug in MSDIA that leads to a crash when it encounters // a fixed-size array of `u8` or something zero-sized in a diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs index 66ae9d72c3e..517246cd0b2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs @@ -38,7 +38,7 @@ impl CodegenCx<'ll, '_> { // For MSVC, omit the column number. // Otherwise, emit it. This mimics clang behaviour. // See discussion in https://github.com/rust-lang/rust/issues/42921 - if self.sess().target.target.options.is_like_msvc { + if self.sess().target.options.is_like_msvc { DebugLoc { file, line, col: None } } else { DebugLoc { file, line, col } diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs index a3d6882940a..9face778322 100644 --- a/compiler/rustc_codegen_llvm/src/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -42,7 +42,7 @@ fn declare_raw_fn( // be merged. llvm::SetUnnamedAddress(llfn, llvm::UnnamedAddr::Global); - if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.target.options.disable_redzone) { + if cx.tcx.sess.opts.cg.no_redzone.unwrap_or(cx.tcx.sess.target.options.disable_redzone) { llvm::Attribute::NoRedZone.apply_llfn(Function, llfn); } diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index e76e86f5651..e78a4ea2e3c 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -334,8 +334,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { self.call(expect, &[cond, self.const_bool(expected)], None) } - fn sideeffect(&mut self) { - if self.tcx.sess.opts.debugging_opts.insert_sideeffect { + fn sideeffect(&mut self, unconditional: bool) { + if unconditional || self.tcx.sess.opts.debugging_opts.insert_sideeffect { let fnname = self.get_intrinsic(&("llvm.sideeffect")); self.call(fnname, &[], None); } @@ -367,7 +367,7 @@ fn try_intrinsic( bx.store(bx.const_i32(0), dest, ret_align); } else if wants_msvc_seh(bx.sess()) { codegen_msvc_try(bx, try_func, data, catch_func, dest); - } else if bx.sess().target.target.options.is_like_emscripten { + } else if bx.sess().target.options.is_like_emscripten { codegen_emcc_try(bx, try_func, data, catch_func, dest); } else { codegen_gnu_try(bx, try_func, data, catch_func, dest); @@ -390,7 +390,7 @@ fn codegen_msvc_try( ) { let llfn = get_rust_try_fn(bx, &mut |mut bx| { bx.set_personality_fn(bx.eh_personality()); - bx.sideeffect(); + bx.sideeffect(false); let mut normal = bx.build_sibling_block("normal"); let mut catchswitch = bx.build_sibling_block("catchswitch"); @@ -553,7 +553,7 @@ fn codegen_gnu_try( // call %catch_func(%data, %ptr) // ret 1 - bx.sideeffect(); + bx.sideeffect(false); let mut then = bx.build_sibling_block("then"); let mut catch = bx.build_sibling_block("catch"); @@ -615,7 +615,7 @@ fn codegen_emcc_try( // call %catch_func(%data, %catch_data) // ret 1 - bx.sideeffect(); + bx.sideeffect(false); let mut then = bx.build_sibling_block("then"); let mut catch = bx.build_sibling_block("catch"); @@ -1722,10 +1722,10 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> { match ty.kind() { ty::Int(t) => { - Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true)) + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), true)) } ty::Uint(t) => { - Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false)) + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), false)) } _ => None, } diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 1237b39b300..5974b59d39e 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -23,18 +23,17 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig}; use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ErrorReported, FatalError, Handler}; -use rustc_middle::dep_graph::{DepGraph, WorkProduct}; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_serialize::json; -use rustc_session::config::{self, OptLevel, OutputFilenames, PrintRequest}; +use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest}; use rustc_session::Session; use rustc_span::symbol::Symbol; use std::any::Any; use std::ffi::CStr; -use std::fs; use std::sync::Arc; mod back { @@ -116,6 +115,9 @@ impl ExtraBackendMethods for LlvmCodegenBackend { fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str { llvm_util::target_cpu(sess) } + fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str> { + llvm_util::tune_cpu(sess) + } } impl WriteBackendMethods for LlvmCodegenBackend { @@ -249,11 +251,11 @@ impl CodegenBackend for LlvmCodegenBackend { } fn provide(&self, providers: &mut ty::query::Providers) { - attributes::provide(providers); + attributes::provide_both(providers); } fn provide_extern(&self, providers: &mut ty::query::Providers) { - attributes::provide_extern(providers); + attributes::provide_both(providers); } fn codegen_crate<'tcx>( @@ -274,47 +276,27 @@ impl CodegenBackend for LlvmCodegenBackend { &self, ongoing_codegen: Box<dyn Any>, sess: &Session, - dep_graph: &DepGraph, - ) -> Result<Box<dyn Any>, ErrorReported> { + ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> { let (codegen_results, work_products) = ongoing_codegen .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<LlvmCodegenBackend>>() .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box<Any>") .join(sess); - if sess.opts.debugging_opts.incremental_info { - rustc_codegen_ssa::back::write::dump_incremental_data(&codegen_results); - } - sess.time("serialize_work_products", move || { - rustc_incremental::save_work_product_index(sess, &dep_graph, work_products) + sess.time("llvm_dump_timing_file", || { + if sess.opts.debugging_opts.llvm_time_trace { + llvm_util::time_trace_profiler_finish("llvm_timings.json"); + } }); - sess.compile_status()?; - - Ok(Box::new(codegen_results)) + Ok((codegen_results, work_products)) } fn link( &self, sess: &Session, - codegen_results: Box<dyn Any>, + codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorReported> { - let codegen_results = codegen_results - .downcast::<CodegenResults>() - .expect("Expected CodegenResults, found Box<Any>"); - - if sess.opts.debugging_opts.no_link { - // FIXME: use a binary format to encode the `.rlink` file - let rlink_data = json::encode(&codegen_results).map_err(|err| { - sess.fatal(&format!("failed to encode rlink: {}", err)); - })?; - let rlink_file = outputs.with_extension(config::RLINK_EXT); - fs::write(&rlink_file, rlink_data).map_err(|err| { - sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err)); - })?; - return Ok(()); - } - // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. sess.time("link_crate", || { @@ -331,16 +313,6 @@ impl CodegenBackend for LlvmCodegenBackend { ); }); - // Now that we won't touch anything in the incremental compilation directory - // any more, we can finalize it (which involves renaming it) - rustc_incremental::finalize_session_directory(sess, codegen_results.crate_hash); - - sess.time("llvm_dump_timing_file", || { - if sess.opts.debugging_opts.llvm_time_trace { - llvm_util::time_trace_profiler_finish("llvm_timings.json"); - } - }); - Ok(()) } } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index af3f3e7aa03..4c1fee0106a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2362,4 +2362,10 @@ extern "C" { bytecode_len: usize, ) -> bool; pub fn LLVMRustLinkerFree(linker: &'a mut Linker<'a>); + #[allow(improper_ctypes)] + pub fn LLVMRustComputeLTOCacheKey( + key_out: &RustString, + mod_id: *const c_char, + data: &ThinLTOData, + ); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index ed9b99188bb..53a404ee019 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -118,11 +118,6 @@ pub fn SetUnnamedAddress(global: &'a Value, unnamed: UnnamedAddr) { } } -pub fn set_thread_local(global: &'a Value, is_thread_local: bool) { - unsafe { - LLVMSetThreadLocal(global, is_thread_local as Bool); - } -} pub fn set_thread_local_mode(global: &'a Value, mode: ThreadLocalMode) { unsafe { LLVMSetThreadLocalMode(global, mode); diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index d42020047fd..9c1e1b8fac0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -46,7 +46,7 @@ fn require_inited() { } unsafe fn configure_llvm(sess: &Session) { - let n_args = sess.opts.cg.llvm_args.len() + sess.target.target.options.llvm_args.len(); + let n_args = sess.opts.cg.llvm_args.len() + sess.target.options.llvm_args.len(); let mut llvm_c_strs = Vec::with_capacity(n_args + 1); let mut llvm_args = Vec::with_capacity(n_args + 1); @@ -57,7 +57,7 @@ unsafe fn configure_llvm(sess: &Session) { } let cg_opts = sess.opts.cg.llvm_args.iter(); - let tg_opts = sess.target.target.options.llvm_args.iter(); + let tg_opts = sess.target.options.llvm_args.iter(); let sess_args = cg_opts.chain(tg_opts); let user_specified_args: FxHashSet<_> = @@ -88,7 +88,7 @@ unsafe fn configure_llvm(sess: &Session) { .opts .debugging_opts .merge_functions - .unwrap_or(sess.target.target.options.merge_functions) + .unwrap_or(sess.target.options.merge_functions) { MergeFunctions::Disabled | MergeFunctions::Trampolines => {} MergeFunctions::Aliases => { @@ -96,9 +96,7 @@ unsafe fn configure_llvm(sess: &Session) { } } - if sess.target.target.target_os == "emscripten" - && sess.panic_strategy() == PanicStrategy::Unwind - { + if sess.target.target_os == "emscripten" && sess.panic_strategy() == PanicStrategy::Unwind { add("-enable-emscripten-cxx-exceptions", false); } @@ -122,7 +120,7 @@ unsafe fn configure_llvm(sess: &Session) { llvm::LLVMInitializePasses(); - ::rustc_llvm::initialize_available_targets(); + rustc_llvm::initialize_available_targets(); llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int, llvm_args.as_ptr()); } @@ -140,7 +138,7 @@ pub fn time_trace_profiler_finish(file_name: &str) { // to LLVM or the feature detection code will walk past the end of the feature // array, leading to crashes. pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { - let arch = if sess.target.target.arch == "x86_64" { "x86" } else { &*sess.target.target.arch }; + let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch }; match (arch, s) { ("x86", "pclmulqdq") => "pclmul", ("x86", "rdrand") => "rdrnd", @@ -202,11 +200,7 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) { } } -pub fn target_cpu(sess: &Session) -> &str { - let name = match sess.opts.cg.target_cpu { - Some(ref s) => &**s, - None => &*sess.target.target.options.cpu, - }; +fn handle_native(name: &str) -> &str { if name != "native" { return name; } @@ -217,3 +211,19 @@ pub fn target_cpu(sess: &Session) -> &str { str::from_utf8(slice::from_raw_parts(ptr as *const u8, len)).unwrap() } } + +pub fn target_cpu(sess: &Session) -> &str { + let name = match sess.opts.cg.target_cpu { + Some(ref s) => &**s, + None => &*sess.target.options.cpu, + }; + + handle_native(name) +} + +pub fn tune_cpu(sess: &Session) -> Option<&str> { + match sess.opts.debugging_opts.tune_cpu { + Some(ref s) => Some(handle_native(&**s)), + None => None, + } +} diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 22ed4dd7576..5f820f83a94 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -52,7 +52,7 @@ fn emit_direct_ptr_va_arg( let next = bx.inbounds_gep(addr, &[full_direct_size]); bx.store(next, va_list_addr, bx.tcx().data_layout.pointer_align.abi); - if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.target.target_endian == "big" { + if size.bytes() < slot_size.bytes() && &*bx.tcx().sess.target.target_endian == "big" { let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32); let adjusted = bx.inbounds_gep(addr, &[adjusted_size]); (bx.bitcast(adjusted, bx.cx().type_ptr_to(llty)), addr_align) @@ -105,7 +105,7 @@ fn emit_aapcs_va_arg( let mut end = bx.build_sibling_block("va_arg.end"); let zero = bx.const_i32(0); let offset_align = Align::from_bytes(4).unwrap(); - assert!(&*bx.tcx().sess.target.target.target_endian == "little"); + assert!(&*bx.tcx().sess.target.target_endian == "little"); let gr_type = target_ty.is_any_ptr() || target_ty.is_integral(); let (reg_off, reg_top_index, slot_size) = if gr_type { @@ -171,8 +171,8 @@ pub(super) fn emit_va_arg( ) -> &'ll Value { // Determine the va_arg implementation to use. The LLVM va_arg instruction // is lacking in some instances, so we should only use it as a fallback. - let target = &bx.cx.tcx.sess.target.target; - let arch = &bx.cx.tcx.sess.target.target.arch; + let target = &bx.cx.tcx.sess.target; + let arch = &bx.cx.tcx.sess.target.arch; match (&**arch, target.options.is_like_windows) { // Windows x86 ("x86", true) => { diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs index f83b4b2b0c0..ef722ecb599 100644 --- a/compiler/rustc_codegen_ssa/src/back/archive.rs +++ b/compiler/rustc_codegen_ssa/src/back/archive.rs @@ -9,9 +9,7 @@ pub fn find_library(name: Symbol, search_paths: &[PathBuf], sess: &Session) -> P // times show up as foo.lib let oslibname = format!( "{}{}{}", - sess.target.target.options.staticlib_prefix, - name, - sess.target.target.options.staticlib_suffix + sess.target.options.staticlib_prefix, name, sess.target.options.staticlib_suffix ); let unixlibname = format!("lib{}.a", name); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 010fd4e9c5a..63d0a88858e 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -15,7 +15,7 @@ use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; use rustc_target::spec::crt_objects::{CrtObjects, CrtObjectsFallback}; use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor}; -use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel}; +use rustc_target::spec::{PanicStrategy, RelocModel, RelroLevel, Target}; use super::archive::ArchiveBuilder; use super::command::Command; @@ -152,7 +152,7 @@ fn get_linker( _ => match flavor { LinkerFlavor::Lld(f) => Command::lld(linker, f), LinkerFlavor::Msvc - if sess.opts.cg.linker.is_none() && sess.target.target.options.linker.is_none() => + if sess.opts.cg.linker.is_none() && sess.target.options.linker.is_none() => { Command::new(msvc_tool.as_ref().map(|t| t.path()).unwrap_or(linker)) } @@ -163,7 +163,7 @@ fn get_linker( // UWP apps have API restrictions enforced during Store submissions. // To comply with the Windows App Certification Kit, // MSVC needs to link with the Store versions of the runtime libraries (vcruntime, msvcrt, etc). - let t = &sess.target.target; + let t = &sess.target; if (flavor == LinkerFlavor::Msvc || flavor == LinkerFlavor::Lld(LldFlavor::Link)) && t.target_vendor == "uwp" { @@ -197,7 +197,7 @@ fn get_linker( // PATH for the child. let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths(self_contained); let mut msvc_changed_path = false; - if sess.target.target.options.is_like_msvc { + if sess.target.options.is_like_msvc { if let Some(ref tool) = msvc_tool { cmd.args(tool.args()); for &(ref k, ref v) in tool.env() { @@ -365,7 +365,7 @@ fn link_rlib<'a, B: ArchiveBuilder<'a>>( // After adding all files to the archive, we need to update the // symbol table of the archive. This currently dies on macOS (see // #11162), and isn't necessary there anyway - if !sess.target.target.options.is_like_osx { + if !sess.target.options.is_like_osx { ab.update_symbols(); } } @@ -476,10 +476,10 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( linker::disable_localization(&mut cmd); - for &(ref k, ref v) in &sess.target.target.options.link_env { + for &(ref k, ref v) in &sess.target.options.link_env { cmd.env(k, v); } - for k in &sess.target.target.options.link_env_remove { + for k in &sess.target.options.link_env_remove { cmd.env_remove(k); } @@ -515,7 +515,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // if the linker doesn't support -no-pie then it should not default to // linking executables as pie. Different versions of gcc seem to use // different quotes in the error message so don't check for them. - if sess.target.target.options.linker_is_gnu + if sess.target.options.linker_is_gnu && flavor != LinkerFlavor::Ld && (out.contains("unrecognized command line option") || out.contains("unknown argument")) @@ -535,7 +535,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // Detect '-static-pie' used with an older version of gcc or clang not supporting it. // Fallback from '-static-pie' to '-static' in that case. - if sess.target.target.options.linker_is_gnu + if sess.target.options.linker_is_gnu && flavor != LinkerFlavor::Ld && (out.contains("unrecognized command line option") || out.contains("unknown argument")) @@ -548,7 +548,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( ); // Mirror `add_(pre,post)_link_objects` to replace CRT objects. let self_contained = crt_objects_fallback(sess, crate_type); - let opts = &sess.target.target.options; + let opts = &sess.target.options; let pre_objects = if self_contained { &opts.pre_link_objects_fallback } else { @@ -670,7 +670,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // is not a Microsoft LNK error then suggest a way to fix or // install the Visual Studio build tools. if let Some(code) = prog.status.code() { - if sess.target.target.options.is_like_msvc + if sess.target.options.is_like_msvc && flavor == LinkerFlavor::Msvc // Respect the command line override && sess.opts.cg.linker.is_none() @@ -741,7 +741,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( linker_error.emit(); - if sess.target.target.options.is_like_msvc && linker_not_found { + if sess.target.options.is_like_msvc && linker_not_found { sess.note_without_error( "the msvc targets depend on the msvc linker \ but `link.exe` was not found", @@ -758,7 +758,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>( // On macOS, debuggers need this utility to get run to do some munging of // the symbols. Note, though, that if the object files are being preserved // for their debug information there's no need for us to run dsymutil. - if sess.target.target.options.is_like_osx + if sess.target.options.is_like_osx && sess.opts.debuginfo != DebugInfo::None && !preserve_objects_for_their_debuginfo(sess) { @@ -776,7 +776,7 @@ fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linke let needs_runtime = match crate_type { CrateType::Executable => true, CrateType::Dylib | CrateType::Cdylib | CrateType::ProcMacro => { - sess.target.target.options.is_like_osx + sess.target.options.is_like_osx } CrateType::Rlib | CrateType::Staticlib => false, }; @@ -846,7 +846,7 @@ pub fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) -> bool // If our target enables builtin function lowering in LLVM then the // crates providing these functions don't participate in LTO (e.g. // no_builtins or compiler builtins crates). - !sess.target.target.options.no_builtins + !sess.target.options.no_builtins && (info.compiler_builtins == Some(cnum) || info.is_no_builtins.contains(&cnum)) } @@ -906,10 +906,10 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { } else if stem == "link" || stem == "lld-link" { LinkerFlavor::Msvc } else if stem == "lld" || stem == "rust-lld" { - LinkerFlavor::Lld(sess.target.target.options.lld_flavor) + LinkerFlavor::Lld(sess.target.options.lld_flavor) } else { // fall back to the value in the target spec - sess.target.target.linker_flavor + sess.target.linker_flavor }; Some((linker, flavor)) @@ -926,8 +926,8 @@ fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) { if let Some(ret) = infer_from( sess, - sess.target.target.options.linker.clone().map(PathBuf::from), - Some(sess.target.target.linker_flavor), + sess.target.options.linker.clone().map(PathBuf::from), + Some(sess.target.linker_flavor), ) { return ret; } @@ -962,7 +962,7 @@ fn preserve_objects_for_their_debuginfo(sess: &Session) -> bool { // Basically as a result this just means that if we're on OSX and we're // *not* running dsymutil then the object files are the only source of truth // for debug information, so we must preserve them. - if sess.target.target.options.is_like_osx { + if sess.target.options.is_like_osx { return !sess.opts.debugging_opts.run_dsymutil; } @@ -988,7 +988,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { NativeLibKind::StaticNoBundle | NativeLibKind::Dylib | NativeLibKind::Unspecified => { - if sess.target.target.options.is_like_msvc { + if sess.target.options.is_like_msvc { Some(format!("{}.lib", name)) } else { Some(format!("-l{}", name)) @@ -1070,16 +1070,13 @@ fn exec_linker( let mut args = String::new(); for arg in cmd2.take_args() { args.push_str( - &Escape { - arg: arg.to_str().unwrap(), - is_like_msvc: sess.target.target.options.is_like_msvc, - } - .to_string(), + &Escape { arg: arg.to_str().unwrap(), is_like_msvc: sess.target.options.is_like_msvc } + .to_string(), ); args.push('\n'); } let file = tmpdir.join("linker-arguments"); - let bytes = if sess.target.target.options.is_like_msvc { + let bytes = if sess.target.options.is_like_msvc { let mut out = Vec::with_capacity((1 + args.len()) * 2); // start the stream with a UTF-16 BOM for c in std::iter::once(0xFEFF).chain(args.encode_utf16()) { @@ -1195,7 +1192,7 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { }; // Adjust the output kind to target capabilities. - let opts = &sess.target.target.options; + let opts = &sess.target.options; let pic_exe_supported = opts.position_independent_executables; let static_pic_exe_supported = opts.static_position_independent_executables; let static_dylib_supported = opts.crt_static_allows_dylibs; @@ -1236,14 +1233,14 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { return self_contained; } - match sess.target.target.options.crt_objects_fallback { + match sess.target.options.crt_objects_fallback { // FIXME: Find a better heuristic for "native musl toolchain is available", // based on host and linker path, for example. // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237). Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)), Some(CrtObjectsFallback::Mingw) => { - sess.host == sess.target.target - && sess.target.target.target_vendor != "uwp" + sess.host == sess.target + && sess.target.target_vendor != "uwp" && detect_self_contained_mingw(&sess) } // FIXME: Figure out cases in which WASM needs to link with a native toolchain. @@ -1259,7 +1256,7 @@ fn add_pre_link_objects( link_output_kind: LinkOutputKind, self_contained: bool, ) { - let opts = &sess.target.target.options; + let opts = &sess.target.options; let objects = if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects }; for obj in objects.get(&link_output_kind).iter().copied().flatten() { @@ -1274,7 +1271,7 @@ fn add_post_link_objects( link_output_kind: LinkOutputKind, self_contained: bool, ) { - let opts = &sess.target.target.options; + let opts = &sess.target.options; let objects = if self_contained { &opts.post_link_objects_fallback } else { &opts.post_link_objects }; for obj in objects.get(&link_output_kind).iter().copied().flatten() { @@ -1285,7 +1282,7 @@ fn add_post_link_objects( /// Add arbitrary "pre-link" args defined by the target spec or from command line. /// FIXME: Determine where exactly these args need to be inserted. fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { - if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { + if let Some(args) = sess.target.options.pre_link_args.get(&flavor) { cmd.args(args); } cmd.args(&sess.opts.debugging_opts.pre_link_args); @@ -1293,13 +1290,13 @@ fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) /// Add a link script embedded in the target, if applicable. fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_type: CrateType) { - match (crate_type, &sess.target.target.options.link_script) { + match (crate_type, &sess.target.options.link_script) { (CrateType::Cdylib | CrateType::Executable, Some(script)) => { - if !sess.target.target.options.linker_is_gnu { + if !sess.target.options.linker_is_gnu { sess.fatal("can only use link script when linking with GNU-like linker"); } - let file_name = ["rustc", &sess.target.target.llvm_target, "linkfile.ld"].join("-"); + let file_name = ["rustc", &sess.target.llvm_target, "linkfile.ld"].join("-"); let path = tmpdir.join(file_name); if let Err(e) = fs::write(&path, script) { @@ -1338,15 +1335,15 @@ fn add_late_link_args( *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic) }); if any_dynamic_crate { - if let Some(args) = sess.target.target.options.late_link_args_dynamic.get(&flavor) { + if let Some(args) = sess.target.options.late_link_args_dynamic.get(&flavor) { cmd.args(args); } } else { - if let Some(args) = sess.target.target.options.late_link_args_static.get(&flavor) { + if let Some(args) = sess.target.options.late_link_args_static.get(&flavor) { cmd.args(args); } } - if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { + if let Some(args) = sess.target.options.late_link_args.get(&flavor) { cmd.args(args); } } @@ -1354,7 +1351,7 @@ fn add_late_link_args( /// Add arbitrary "post-link" args defined by the target spec. /// FIXME: Determine where exactly these args need to be inserted. fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { - if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { + if let Some(args) = sess.target.options.post_link_args.get(&flavor) { cmd.args(args); } } @@ -1456,7 +1453,7 @@ fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: /// Add options making relocation sections in the produced ELF files read-only /// and suppressing lazy binding. fn add_relro_args(cmd: &mut dyn Linker, sess: &Session) { - match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.target.options.relro_level) { + match sess.opts.debugging_opts.relro_level.unwrap_or(sess.target.options.relro_level) { RelroLevel::Full => cmd.full_relro(), RelroLevel::Partial => cmd.partial_relro(), RelroLevel::Off => cmd.no_relro(), @@ -1487,9 +1484,9 @@ fn add_rpath_args( let mut rpath_config = RPathConfig { used_crates: &codegen_results.crate_info.used_crates_dynamic, out_filename: out_filename.to_path_buf(), - has_rpath: sess.target.target.options.has_rpath, - is_like_osx: sess.target.target.options.is_like_osx, - linker_is_gnu: sess.target.target.options.linker_is_gnu, + has_rpath: sess.target.options.has_rpath, + is_like_osx: sess.target.options.is_like_osx, + linker_is_gnu: sess.target.options.linker_is_gnu, get_install_prefix_lib_path: &mut get_install_prefix_lib_path, }; cmd.args(&rpath::get_rpath_flags(&mut rpath_config)); @@ -1517,7 +1514,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( let base_cmd = get_linker(sess, path, flavor, crt_objects_fallback); // FIXME: Move `/LIBPATH` addition for uwp targets from the linker construction // to the linker args construction. - assert!(base_cmd.get_args().is_empty() || sess.target.target.target_vendor == "uwp"); + assert!(base_cmd.get_args().is_empty() || sess.target.target_vendor == "uwp"); let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor, target_cpu); let link_output_kind = link_output_kind(sess, crate_type); @@ -1531,7 +1528,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( add_link_script(cmd, sess, tmpdir, crate_type); // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable { + if sess.target.options.is_like_fuchsia && crate_type == CrateType::Executable { let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) { "asan/" } else { @@ -1541,7 +1538,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( } // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - if sess.target.target.options.eh_frame_header { + if sess.target.options.eh_frame_header { cmd.add_eh_frame_header(); } @@ -1554,7 +1551,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); // NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER - if sess.target.target.options.is_like_emscripten { + if sess.target.options.is_like_emscripten { cmd.arg("-s"); cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { "DISABLE_EXCEPTION_CATCHING=1" @@ -1582,7 +1579,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( cmd.output_filename(out_filename); // OBJECT-FILES-NO, AUDIT-ORDER - if crate_type == CrateType::Executable && sess.target.target.options.is_like_windows { + if crate_type == CrateType::Executable && sess.target.options.is_like_windows { if let Some(ref s) = codegen_results.windows_subsystem { cmd.subsystem(s); } @@ -1626,7 +1623,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // OBJECT-FILES-NO, AUDIT-ORDER // We want to prevent the compiler from accidentally leaking in any system libraries, // so by default we tell linkers not to link to any default libraries. - if !sess.opts.cg.default_linker_libraries && sess.target.target.options.no_default_libraries { + if !sess.opts.cg.default_linker_libraries && sess.target.options.no_default_libraries { cmd.no_default_libraries(); } @@ -1845,12 +1842,8 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( } // Converts a library file-stem into a cc -l argument - fn unlib<'a>(config: &config::Config, stem: &'a str) -> &'a str { - if stem.starts_with("lib") && !config.target.options.is_like_windows { - &stem[3..] - } else { - stem - } + fn unlib<'a>(target: &Target, stem: &'a str) -> &'a str { + if stem.starts_with("lib") && !target.options.is_like_windows { &stem[3..] } else { stem } } // Adds the static "rlib" versions of all crates to the command line. @@ -1945,7 +1938,7 @@ fn add_upstream_rust_crates<'a, B: ArchiveBuilder<'a>>( // though, so we let that object file slide. let skip_because_lto = are_upstream_rust_objects_already_included(sess) && is_rust_object - && (sess.target.target.options.no_builtins + && (sess.target.options.no_builtins || !codegen_results.crate_info.is_no_builtins.contains(&cnum)); if skip_because_cfg_say_so || skip_because_lto { @@ -2088,10 +2081,10 @@ fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { } fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { - let arch = &sess.target.target.arch; - let os = &sess.target.target.target_os; - let llvm_target = &sess.target.target.llvm_target; - if sess.target.target.target_vendor != "apple" + let arch = &sess.target.arch; + let os = &sess.target.target_os; + let llvm_target = &sess.target.llvm_target; + if sess.target.target_vendor != "apple" || !matches!(os.as_str(), "ios" | "tvos") || flavor != LinkerFlavor::Gcc { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 0ddf8bd316f..3e13a1daecd 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -184,7 +184,7 @@ impl<'a> GccLinker<'a> { // * On OSX they have their own linker, not binutils' // * For WebAssembly the only functional linker is LLD, which doesn't // support hint flags - !self.sess.target.target.options.is_like_osx && self.sess.target.target.arch != "wasm32" + !self.sess.target.options.is_like_osx && self.sess.target.arch != "wasm32" } // Some platforms take hints about whether a library is static or dynamic. @@ -221,10 +221,8 @@ impl<'a> GccLinker<'a> { let opt_level = match self.sess.opts.optimize { config::OptLevel::No => "O0", config::OptLevel::Less => "O1", - config::OptLevel::Default => "O2", + config::OptLevel::Default | config::OptLevel::Size | config::OptLevel::SizeMin => "O2", config::OptLevel::Aggressive => "O3", - config::OptLevel::Size => "Os", - config::OptLevel::SizeMin => "Oz", }; self.linker_arg(&format!("-plugin-opt={}", opt_level)); @@ -234,7 +232,7 @@ impl<'a> GccLinker<'a> { fn build_dylib(&mut self, out_filename: &Path) { // On mac we need to tell the linker to let this library be rpathed - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { self.cmd.arg("-dynamiclib"); self.linker_arg("-dylib"); @@ -250,7 +248,7 @@ impl<'a> GccLinker<'a> { } } else { self.cmd.arg("-shared"); - if self.sess.target.target.options.is_like_windows { + if self.sess.target.options.is_like_windows { // The output filename already contains `dll_suffix` so // the resulting import library will have a name in the // form of libfoo.dll.a @@ -258,9 +256,9 @@ impl<'a> GccLinker<'a> { out_filename.file_name().and_then(|file| file.to_str()).map(|file| { format!( "{}{}{}", - self.sess.target.target.options.staticlib_prefix, + self.sess.target.options.staticlib_prefix, file, - self.sess.target.target.options.staticlib_suffix + self.sess.target.options.staticlib_suffix ) }); if let Some(implib_name) = implib_name { @@ -282,7 +280,7 @@ impl<'a> Linker for GccLinker<'a> { fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { match output_kind { LinkOutputKind::DynamicNoPicExe => { - if !self.is_ld && self.sess.target.target.options.linker_is_gnu { + if !self.is_ld && self.sess.target.options.linker_is_gnu { self.cmd.arg("-no-pie"); } } @@ -293,7 +291,7 @@ impl<'a> Linker for GccLinker<'a> { LinkOutputKind::StaticNoPicExe => { // `-static` works for both gcc wrapper and ld. self.cmd.arg("-static"); - if !self.is_ld && self.sess.target.target.options.linker_is_gnu { + if !self.is_ld && self.sess.target.options.linker_is_gnu { self.cmd.arg("-no-pie"); } } @@ -322,7 +320,7 @@ impl<'a> Linker for GccLinker<'a> { // any `#[link]` attributes in the `libc` crate, see #72782 for details. // FIXME: Switch to using `#[link]` attributes in the `libc` crate // similarly to other targets. - if self.sess.target.target.target_os == "vxworks" + if self.sess.target.target_os == "vxworks" && matches!( output_kind, LinkOutputKind::StaticNoPicExe @@ -387,7 +385,7 @@ impl<'a> Linker for GccLinker<'a> { // functions, etc. fn link_whole_staticlib(&mut self, lib: Symbol, search_path: &[PathBuf]) { self.hint_static(); - let target = &self.sess.target.target; + let target = &self.sess.target; if !target.options.is_like_osx { self.linker_arg("--whole-archive").cmd.arg(format!("-l{}", lib)); self.linker_arg("--no-whole-archive"); @@ -402,7 +400,7 @@ impl<'a> Linker for GccLinker<'a> { fn link_whole_rlib(&mut self, lib: &Path) { self.hint_static(); - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { self.linker_arg("-force_load"); self.linker_arg(&lib); } else { @@ -426,9 +424,9 @@ impl<'a> Linker for GccLinker<'a> { // -dead_strip can't be part of the pre_link_args because it's also used // for partial linking when using multiple codegen units (-r). So we // insert it here. - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { self.linker_arg("-dead_strip"); - } else if self.sess.target.target.options.is_like_solaris { + } else if self.sess.target.options.is_like_solaris { self.linker_arg("-zignore"); // If we're building a dylib, we don't use --gc-sections because LLVM @@ -442,7 +440,7 @@ impl<'a> Linker for GccLinker<'a> { } fn optimize(&mut self) { - if !self.sess.target.target.options.linker_is_gnu { + if !self.sess.target.options.linker_is_gnu { return; } @@ -456,7 +454,7 @@ impl<'a> Linker for GccLinker<'a> { } fn pgo_gen(&mut self) { - if !self.sess.target.target.options.linker_is_gnu { + if !self.sess.target.options.linker_is_gnu { return; } @@ -506,7 +504,7 @@ impl<'a> Linker for GccLinker<'a> { fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) { // Symbol visibility in object files typically takes care of this. if crate_type == CrateType::Executable - && self.sess.target.target.options.override_export_symbols.is_none() + && self.sess.target.options.override_export_symbols.is_none() { return; } @@ -515,7 +513,7 @@ impl<'a> Linker for GccLinker<'a> { // The object files have far more public symbols than we actually want to export, // so we hide them all here. - if !self.sess.target.target.options.limit_rdylib_exports { + if !self.sess.target.options.limit_rdylib_exports { return; } @@ -523,13 +521,13 @@ impl<'a> Linker for GccLinker<'a> { return; } - let is_windows = self.sess.target.target.options.is_like_windows; + let is_windows = self.sess.target.options.is_like_windows; let mut arg = OsString::new(); let path = tmpdir.join(if is_windows { "list.def" } else { "list" }); debug!("EXPORTED SYMBOLS:"); - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { // Write a plain, newline-separated list of symbols let res: io::Result<()> = try { let mut f = BufWriter::new(File::create(&path)?); @@ -575,12 +573,12 @@ impl<'a> Linker for GccLinker<'a> { } } - if self.sess.target.target.options.is_like_osx { + if self.sess.target.options.is_like_osx { if !self.is_ld { arg.push("-Wl,") } arg.push("-exported_symbols_list,"); - } else if self.sess.target.target.options.is_like_solaris { + } else if self.sess.target.options.is_like_solaris { if !self.is_ld { arg.push("-Wl,") } @@ -1205,7 +1203,7 @@ impl<'a> Linker for WasmLd<'a> { } fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> { - if let Some(ref exports) = tcx.sess.target.target.options.override_export_symbols { + if let Some(ref exports) = tcx.sess.target.options.override_export_symbols { return exports.clone(); } @@ -1295,7 +1293,7 @@ impl<'a> Linker for PtxLinker<'a> { // Provide the linker with fallback to internal `target-cpu`. self.cmd.arg("--fallback-arch").arg(match self.sess.opts.cg.target_cpu { Some(ref s) => s, - None => &self.sess.target.target.options.cpu, + None => &self.sess.target.options.cpu, }); } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 51cc1ada432..dd8d751d045 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -229,8 +229,8 @@ fn exported_symbols_provider_local( // needs to be exported. // However, on platforms that don't allow for Rust dylibs, having // external linkage is enough for monomorphization to be linked to. - let need_visibility = tcx.sess.target.target.options.dynamic_linking - && !tcx.sess.target.target.options.only_cdylib; + let need_visibility = + tcx.sess.target.options.dynamic_linking && !tcx.sess.target.options.only_cdylib; let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); @@ -391,7 +391,7 @@ fn symbol_export_level(tcx: TyCtxt<'_>, sym_def_id: DefId) -> SymbolExportLevel codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); if is_extern && !std_internal { - let target = &tcx.sess.target.target.llvm_target; + let target = &tcx.sess.target.llvm_target; // WebAssembly cannot export data symbols, so reduce their export level if target.contains("emscripten") { if let Some(Node::Item(&hir::Item { kind: hir::ItemKind::Static(..), .. })) = diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 0edf0fcd1a2..4d2cea18dcc 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -13,7 +13,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::profiling::TimingGuard; use rustc_data_structures::profiling::VerboseTimingGuard; -use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_errors::emitter::Emitter; use rustc_errors::{DiagnosticId, FatalError, Handler, Level}; @@ -140,7 +139,7 @@ impl ModuleConfig { let emit_obj = if !should_emit_obj { EmitObj::None - } else if sess.target.target.options.obj_is_bitcode + } else if sess.target.options.obj_is_bitcode || (sess.opts.cg.linker_plugin_lto.enabled() && !no_builtins) { // This case is selected if the target uses objects as bitcode, or @@ -222,11 +221,11 @@ impl ModuleConfig { false ), emit_obj, - bc_cmdline: sess.target.target.options.bitcode_llvm_cmdline.clone(), + bc_cmdline: sess.target.options.bitcode_llvm_cmdline.clone(), verify_llvm_ir: sess.verify_llvm_ir(), no_prepopulate_passes: sess.opts.cg.no_prepopulate_passes, - no_builtins: no_builtins || sess.target.target.options.no_builtins, + no_builtins: no_builtins || sess.target.options.no_builtins, // Exclude metadata and allocator modules from time_passes output, // since they throw off the "LLVM passes" measurement. @@ -253,7 +252,7 @@ impl ModuleConfig { .opts .debugging_opts .merge_functions - .unwrap_or(sess.target.target.options.merge_functions) + .unwrap_or(sess.target.options.merge_functions) { MergeFunctions::Disabled => false, MergeFunctions::Trampolines | MergeFunctions::Aliases => { @@ -308,7 +307,7 @@ pub struct CodegenContext<B: WriteBackendMethods> { pub allocator_module_config: Arc<ModuleConfig>, pub tm_factory: TargetMachineFactory<B>, pub msvc_imps_needed: bool, - pub target_pointer_width: String, + pub target_pointer_width: u32, pub target_arch: String, pub debuginfo: config::DebugInfo, @@ -389,7 +388,7 @@ fn need_bitcode_in_object(sess: &Session) -> bool { let requested_for_rlib = sess.opts.cg.embed_bitcode && sess.crate_types().contains(&CrateType::Rlib) && sess.opts.output_types.contains_key(&OutputType::Exe); - let forced_by_target = sess.target.target.options.forces_embed_bitcode; + let forced_by_target = sess.target.options.forces_embed_bitcode; requested_for_rlib || forced_by_target } @@ -414,7 +413,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( let sess = tcx.sess; let crate_name = tcx.crate_name(LOCAL_CRATE); - let crate_hash = tcx.crate_hash(LOCAL_CRATE); let no_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins); let is_compiler_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::compiler_builtins); @@ -463,7 +461,6 @@ pub fn start_async_codegen<B: ExtraBackendMethods>( OngoingCodegen { backend, crate_name, - crate_hash, metadata, windows_subsystem, linker_info, @@ -658,15 +655,6 @@ fn produce_final_output_artifacts( // These are used in linking steps and will be cleaned up afterward. } -pub fn dump_incremental_data(_codegen_results: &CodegenResults) { - // FIXME(mw): This does not work at the moment because the situation has - // become more complicated due to incremental LTO. Now a CGU - // can have more than two caching states. - // println!("[incremental] Re-using {} out of {} modules", - // codegen_results.modules.iter().filter(|m| m.pre_existing).count(), - // codegen_results.modules.len()); -} - pub enum WorkItem<B: WriteBackendMethods> { /// Optimize a newly codegened, totally unoptimized module. Optimize(ModuleCodegen<B::Module>), @@ -1034,8 +1022,8 @@ fn start_executing_work<B: ExtraBackendMethods>( tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol)), total_cgus, msvc_imps_needed: msvc_imps_needed(tcx), - target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), - target_arch: tcx.sess.target.target.arch.clone(), + target_pointer_width: tcx.sess.target.pointer_width, + target_arch: tcx.sess.target.arch.clone(), debuginfo: tcx.sess.opts.debuginfo, }; @@ -1175,7 +1163,7 @@ fn start_executing_work<B: ExtraBackendMethods>( // necessary. There's already optimizations in place to avoid sending work // back to the coordinator if LTO isn't requested. return thread::spawn(move || { - let max_workers = ::num_cpus::get(); + let max_workers = num_cpus::get(); let mut worker_id_counter = 0; let mut free_worker_ids = Vec::new(); let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| { @@ -1531,8 +1519,6 @@ fn start_executing_work<B: ExtraBackendMethods>( } } -pub const CODEGEN_WORKER_ID: usize = usize::MAX; - /// `FatalError` is explicitly not `Send`. #[must_use] pub struct WorkerFatalError; @@ -1720,7 +1706,6 @@ impl SharedEmitterMain { pub struct OngoingCodegen<B: ExtraBackendMethods> { pub backend: B, pub crate_name: Symbol, - pub crate_hash: Svh, pub metadata: EncodedMetadata, pub windows_subsystem: Option<String>, pub linker_info: LinkerInfo, @@ -1766,7 +1751,6 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> { ( CodegenResults { crate_name: self.crate_name, - crate_hash: self.crate_hash, metadata: self.metadata, windows_subsystem: self.windows_subsystem, linker_info: self.linker_info, @@ -1881,11 +1865,11 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { // something is wrong with commandline arg validation. assert!( !(tcx.sess.opts.cg.linker_plugin_lto.enabled() - && tcx.sess.target.target.options.is_like_windows + && tcx.sess.target.options.is_like_windows && tcx.sess.opts.cg.prefer_dynamic) ); - tcx.sess.target.target.options.is_like_windows && + tcx.sess.target.options.is_like_windows && tcx.sess.crate_types().iter().any(|ct| *ct == CrateType::Rlib) && // ThinLTO can't handle this workaround in all cases, so we don't // emit the `__imp_` symbols. Instead we make them unnecessary by disallowing diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 8e6f8e193c0..4d937609132 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -327,7 +327,7 @@ fn cast_shift_rhs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( /// currently uses SEH-ish unwinding with DWARF info tables to the side (same as /// 64-bit MinGW) instead of "full SEH". pub fn wants_msvc_seh(sess: &Session) -> bool { - sess.target.target.options.is_like_msvc + sess.target.options.is_like_msvc } pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( @@ -393,7 +393,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) -> Bx::Function { // The entry function is either `int main(void)` or `int main(int argc, char **argv)`, // depending on whether the target needs `argc` and `argv` to be passed in. - let llfty = if cx.sess().target.target.options.main_needs_argc_argv { + let llfty = if cx.sess().target.options.main_needs_argc_argv { cx.type_func(&[cx.type_int(), cx.type_ptr_to(cx.type_i8p())], cx.type_int()) } else { cx.type_func(&[], cx.type_int()) @@ -464,7 +464,7 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( cx: &'a Bx::CodegenCx, bx: &mut Bx, ) -> (Bx::Value, Bx::Value) { - if cx.sess().target.target.options.main_needs_argc_argv { + if cx.sess().target.options.main_needs_argc_argv { // Params from native `main()` used as args for rust start function let param_argc = bx.get_param(0); let param_argv = bx.get_param(1); @@ -479,8 +479,6 @@ fn get_argc_argv<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } -pub const CODEGEN_WORKER_ID: usize = usize::MAX; - pub fn codegen_crate<B: ExtraBackendMethods>( backend: B, tcx: TyCtxt<'tcx>, @@ -695,7 +693,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( total_codegen_time.into_inner(), ); - ::rustc_incremental::assert_module_sources::assert_module_sources(tcx); + rustc_incremental::assert_module_sources::assert_module_sources(tcx); symbol_names_test::report_symbol_names(tcx); @@ -754,8 +752,8 @@ impl<B: ExtraBackendMethods> Drop for AbortCodegenOnDrop<B> { } fn finalize_tcx(tcx: TyCtxt<'_>) { - tcx.sess.time("assert_dep_graph", || ::rustc_incremental::assert_dep_graph(tcx)); - tcx.sess.time("serialize_dep_graph", || ::rustc_incremental::save_dep_graph(tcx)); + tcx.sess.time("assert_dep_graph", || rustc_incremental::assert_dep_graph(tcx)); + tcx.sess.time("serialize_dep_graph", || rustc_incremental::save_dep_graph(tcx)); // We assume that no queries are run past here. If there are new queries // after this point, they'll show up as "<unknown>" in self-profiling data. diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index 45ecb793387..c4c51d146a6 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -33,7 +33,7 @@ pub fn push_debuginfo_type_name<'tcx>( ) { // When targeting MSVC, emit C++ style type names for compatibility with // .natvis visualizers (and perhaps other existing native debuggers?) - let cpp_like_names = tcx.sess.target.target.options.is_like_msvc; + let cpp_like_names = tcx.sess.target.options.is_like_msvc; match *t.kind() { ty::Bool => output.push_str("bool"), diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index e34371ef59a..70b92b234e9 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -21,7 +21,6 @@ extern crate tracing; extern crate rustc_middle; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; use rustc_hir::def_id::CrateNum; use rustc_hir::LangItem; @@ -134,7 +133,6 @@ pub struct CodegenResults { pub modules: Vec<CompiledModule>, pub allocator_module: Option<CompiledModule>, pub metadata_module: Option<CompiledModule>, - pub crate_hash: Svh, pub metadata: rustc_middle::middle::cstore::EncodedMetadata, pub windows_subsystem: Option<String>, pub linker_info: back::linker::LinkerInfo, @@ -144,6 +142,7 @@ pub struct CodegenResults { pub fn provide(providers: &mut Providers) { crate::back::symbol_export::provide(providers); crate::base::provide_both(providers); + crate::target_features::provide(providers); } pub fn provide_extern(providers: &mut Providers) { diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 703a17b200a..bec0a84cac0 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -12,9 +12,9 @@ use crate::MemFlags; use rustc_ast as ast; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; -use rustc_middle::mir; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::AssertKind; +use rustc_middle::mir::{self, SwitchTargets}; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; @@ -24,8 +24,6 @@ use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; use rustc_target::abi::{self, LayoutOf}; use rustc_target::spec::abi::Abi; -use std::borrow::Cow; - /// Used by `FunctionCx::codegen_terminator` for emitting common patterns /// e.g., creating a basic block, calling a function, etc. struct TerminatorCodegenHelper<'tcx> { @@ -165,7 +163,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> { target <= self.bb && target.start_location().is_predecessor_of(self.bb.start_location(), mir) }) { - bx.sideeffect(); + bx.sideeffect(false); } } } @@ -198,42 +196,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mut bx: Bx, discr: &mir::Operand<'tcx>, switch_ty: Ty<'tcx>, - values: &Cow<'tcx, [u128]>, - targets: &Vec<mir::BasicBlock>, + targets: &SwitchTargets, ) { let discr = self.codegen_operand(&mut bx, &discr); // `switch_ty` is redundant, sanity-check that. assert_eq!(discr.layout.ty, switch_ty); - if targets.len() == 2 { - // If there are two targets, emit br instead of switch - let lltrue = helper.llblock(self, targets[0]); - let llfalse = helper.llblock(self, targets[1]); + helper.maybe_sideeffect(self.mir, &mut bx, targets.all_targets()); + + let mut target_iter = targets.iter(); + if target_iter.len() == 1 { + // If there are two targets (one conditional, one fallback), emit br instead of switch + let (test_value, target) = target_iter.next().unwrap(); + let lltrue = helper.llblock(self, target); + let llfalse = helper.llblock(self, targets.otherwise()); if switch_ty == bx.tcx().types.bool { - helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice()); // Don't generate trivial icmps when switching on bool - if let [0] = values[..] { - bx.cond_br(discr.immediate(), llfalse, lltrue); - } else { - assert_eq!(&values[..], &[1]); - bx.cond_br(discr.immediate(), lltrue, llfalse); + match test_value { + 0 => bx.cond_br(discr.immediate(), llfalse, lltrue), + 1 => bx.cond_br(discr.immediate(), lltrue, llfalse), + _ => bug!(), } } else { let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty)); - let llval = bx.const_uint_big(switch_llty, values[0]); + let llval = bx.const_uint_big(switch_llty, test_value); let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval); - helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice()); bx.cond_br(cmp, lltrue, llfalse); } } else { - helper.maybe_sideeffect(self.mir, &mut bx, targets.as_slice()); - let (otherwise, targets) = targets.split_last().unwrap(); bx.switch( discr.immediate(), - helper.llblock(self, *otherwise), - values - .iter() - .zip(targets) - .map(|(&value, target)| (value, helper.llblock(self, *target))), + helper.llblock(self, targets.otherwise()), + target_iter.map(|(value, target)| (value, helper.llblock(self, target))), ); } } @@ -879,7 +872,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let string = match ty.kind() { ty::Uint(_) => value.to_string(), ty::Int(int_ty) => { - match int_ty.normalize(bx.tcx().sess.target.ptr_width) { + match int_ty.normalize(bx.tcx().sess.target.pointer_width) { ast::IntTy::I8 => (value as i8).to_string(), ast::IntTy::I16 => (value as i16).to_string(), ast::IntTy::I32 => (value as i32).to_string(), @@ -971,12 +964,28 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::TerminatorKind::Goto { target } => { - helper.maybe_sideeffect(self.mir, &mut bx, &[target]); + if bb == target { + // This is an unconditional branch back to this same basic + // block. That means we have something like a `loop {}` + // statement. Currently LLVM miscompiles this because it + // assumes forward progress. We want to prevent this in all + // cases, but that has a fairly high cost to compile times + // currently. Instead, try to handle this specific case + // which comes up commonly in practice (e.g., in embedded + // code). + // + // The `true` here means we insert side effects regardless + // of -Zinsert-sideeffect being passed on unconditional + // branching to the same basic block. + bx.sideeffect(true); + } else { + helper.maybe_sideeffect(self.mir, &mut bx, &[target]); + } helper.funclet_br(self, &mut bx, target); } - mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { - self.codegen_switchint_terminator(helper, bx, discr, switch_ty, values, targets); + mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => { + self.codegen_switchint_terminator(helper, bx, discr, switch_ty, targets); } mir::TerminatorKind::Return => { diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index 14f1ed59a67..2bf1ee43c73 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -580,8 +580,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // stuffs. fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> { match ty.kind() { - ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)), - ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)), + ty::Int(t) => { + Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), true)) + } + ty::Uint(t) => { + Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), false)) + } _ => None, } } diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs index 64d456fb7aa..bff263567bf 100644 --- a/compiler/rustc_codegen_ssa/src/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -153,7 +153,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx.set_personality_fn(cx.eh_personality()); } - bx.sideeffect(); + bx.sideeffect(false); let cleanup_kinds = analyze::cleanup_kinds(&mir); // Allocate a `Block` for every basic block, except diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 91609b22615..e1cc0268723 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -346,8 +346,8 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { .. } => { if variant_index != dataful_variant { - if bx.cx().sess().target.target.arch == "arm" - || bx.cx().sess().target.target.arch == "aarch64" + if bx.cx().sess().target.arch == "arm" + || bx.cx().sess().target.arch == "aarch64" { // FIXME(#34427): as workaround for LLVM bug on ARM, // use memset of 0 before assigning niche value. diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 4c61e21901b..a8d88a95f7a 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -1,3 +1,5 @@ +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_middle::ty::query::Providers; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::symbol::Symbol; @@ -136,7 +138,7 @@ pub fn all_known_features() -> impl Iterator<Item = (&'static str, Option<Symbol } pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Option<Symbol>)] { - match &*sess.target.target.arch { + match &*sess.target.arch { "arm" => ARM_ALLOWED_FEATURES, "aarch64" => AARCH64_ALLOWED_FEATURES, "x86" | "x86_64" => X86_ALLOWED_FEATURES, @@ -148,3 +150,16 @@ pub fn supported_target_features(sess: &Session) -> &'static [(&'static str, Opt _ => &[], } } + +pub(crate) fn provide(providers: &mut Providers) { + providers.supported_target_features = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + if tcx.sess.opts.actually_rustdoc { + // rustdoc needs to be able to document functions that use all the features, so + // whitelist them all + all_known_features().map(|(a, b)| (a.to_string(), b)).collect() + } else { + supported_target_features(tcx.sess).iter().map(|&(a, b)| (a.to_string(), b)).collect() + } + }; +} diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 48c07b00894..3fb189e1984 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -1,10 +1,11 @@ use super::write::WriteBackendMethods; use super::CodegenObject; -use crate::ModuleCodegen; +use crate::{CodegenResults, ModuleCodegen}; use rustc_ast::expand::allocator::AllocatorKind; +use rustc_data_structures::fx::FxHashMap; use rustc_errors::ErrorReported; -use rustc_middle::dep_graph::DepGraph; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoaderDyn}; use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; use rustc_middle::ty::query::Providers; @@ -80,8 +81,7 @@ pub trait CodegenBackend { &self, ongoing_codegen: Box<dyn Any>, sess: &Session, - dep_graph: &DepGraph, - ) -> Result<Box<dyn Any>, ErrorReported>; + ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported>; /// This is called on the returned `Box<dyn Any>` from `join_codegen` /// @@ -91,7 +91,7 @@ pub trait CodegenBackend { fn link( &self, sess: &Session, - codegen_results: Box<dyn Any>, + codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorReported>; } @@ -124,4 +124,5 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se opt_level: config::OptLevel, ) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>; fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str; + fn tune_cpu<'b>(&self, sess: &'b Session) -> Option<&'b str>; } diff --git a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index ccd294d92b2..ac3c99f9c90 100644 --- a/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -20,7 +20,9 @@ pub trait IntrinsicCallMethods<'tcx>: BackendTypes { fn abort(&mut self); fn assume(&mut self, val: Self::Value); fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value; - fn sideeffect(&mut self); + /// Normally, sideeffect is only emitted if -Zinsert-sideeffect is passed; + /// in some cases though we want to emit it regardless. + fn sideeffect(&mut self, unconditional: bool); /// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in /// Rust defined C-variadic functions. fn va_start(&mut self, val: Self::Value) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 698ef6083e6..82518b7f0c3 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -85,7 +85,7 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where } pub trait HasCodegen<'tcx>: - Backend<'tcx> + ::std::ops::Deref<Target = <Self as HasCodegen<'tcx>>::CodegenCx> + Backend<'tcx> + std::ops::Deref<Target = <Self as HasCodegen<'tcx>>::CodegenCx> { type CodegenCx: CodegenMethods<'tcx> + BackendTypes< diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index cec07b977e6..43bc0c83155 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -51,7 +51,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } fn type_int(&self) -> Self::Type { - match &self.sess().target.target.target_c_int_width[..] { + match &self.sess().target.target_c_int_width[..] { "16" => self.type_i16(), "32" => self.type_i32(), "64" => self.type_i64(), diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs index aba0bbbac80..ec2f9597b18 100644 --- a/compiler/rustc_data_structures/src/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -71,8 +71,8 @@ impl Fingerprint { } } -impl ::std::fmt::Display for Fingerprint { - fn fmt(&self, formatter: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { +impl std::fmt::Display for Fingerprint { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(formatter, "{:x}-{:x}", self.0, self.1) } } diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 7cf5202d919..c0193e9fa0c 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -129,7 +129,7 @@ pub enum ProcessResult<O, E> { struct ObligationTreeId(usize); type ObligationTreeIdGenerator = - ::std::iter::Map<::std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>; + std::iter::Map<std::ops::RangeFrom<usize>, fn(usize) -> ObligationTreeId>; pub struct ObligationForest<O: ForestObligation> { /// The list of obligations. In between calls to `process_obligations`, diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index 4807380595d..9a28f8f4e21 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -93,7 +93,7 @@ impl<K: Ord, V> SortedMap<K, V> { /// Iterate over elements, sorted by key #[inline] - pub fn iter(&self) -> ::std::slice::Iter<'_, (K, V)> { + pub fn iter(&self) -> std::slice::Iter<'_, (K, V)> { self.data.iter() } @@ -134,7 +134,7 @@ impl<K: Ord, V> SortedMap<K, V> { R: RangeBounds<K>, { let (start, end) = self.range_slice_indices(range); - self.data.splice(start..end, ::std::iter::empty()); + self.data.splice(start..end, std::iter::empty()); } /// Mutate all keys with the given function `f`. This mutation must not @@ -241,7 +241,7 @@ impl<K: Ord, V> SortedMap<K, V> { impl<K: Ord, V> IntoIterator for SortedMap<K, V> { type Item = (K, V); - type IntoIter = ::std::vec::IntoIter<(K, V)>; + type IntoIter = std::vec::IntoIter<(K, V)>; fn into_iter(self) -> Self::IntoIter { self.data.into_iter() diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index 68875b3fbde..579eb1cb7da 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -20,7 +20,7 @@ pub struct StableHasher { } impl ::std::fmt::Debug for StableHasher { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self.state) } } diff --git a/compiler/rustc_data_structures/src/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs index 0c848eb144d..cc562bc1e4d 100644 --- a/compiler/rustc_data_structures/src/work_queue.rs +++ b/compiler/rustc_data_structures/src/work_queue.rs @@ -14,12 +14,6 @@ pub struct WorkQueue<T: Idx> { } impl<T: Idx> WorkQueue<T> { - /// Creates a new work queue with all the elements from (0..len). - #[inline] - pub fn with_all(len: usize) -> Self { - WorkQueue { deque: (0..len).map(T::new).collect(), set: BitSet::new_filled(len) } - } - /// Creates a new work queue that starts empty, where elements range from (0..len). #[inline] pub fn with_none(len: usize) -> Self { diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index dd9643913ed..d99e335a77a 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -134,9 +134,52 @@ pub fn diagnostics_registry() -> Registry { Registry::new(&rustc_error_codes::DIAGNOSTICS) } +pub struct RunCompiler<'a, 'b> { + at_args: &'a [String], + callbacks: &'b mut (dyn Callbacks + Send), + file_loader: Option<Box<dyn FileLoader + Send + Sync>>, + emitter: Option<Box<dyn Write + Send>>, + make_codegen_backend: + Option<Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>>, +} + +impl<'a, 'b> RunCompiler<'a, 'b> { + pub fn new(at_args: &'a [String], callbacks: &'b mut (dyn Callbacks + Send)) -> Self { + Self { at_args, callbacks, file_loader: None, emitter: None, make_codegen_backend: None } + } + pub fn set_make_codegen_backend( + &mut self, + make_codegen_backend: Option< + Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>, + >, + ) -> &mut Self { + self.make_codegen_backend = make_codegen_backend; + self + } + pub fn set_emitter(&mut self, emitter: Option<Box<dyn Write + Send>>) -> &mut Self { + self.emitter = emitter; + self + } + pub fn set_file_loader( + &mut self, + file_loader: Option<Box<dyn FileLoader + Send + Sync>>, + ) -> &mut Self { + self.file_loader = file_loader; + self + } + pub fn run(self) -> interface::Result<()> { + run_compiler( + self.at_args, + self.callbacks, + self.file_loader, + self.emitter, + self.make_codegen_backend, + ) + } +} // Parse args and run the compiler. This is the primary entry point for rustc. // The FileLoader provides a way to load files from sources other than the file system. -pub fn run_compiler( +fn run_compiler( at_args: &[String], callbacks: &mut (dyn Callbacks + Send), file_loader: Option<Box<dyn FileLoader + Send + Sync>>, @@ -599,7 +642,7 @@ impl RustcDefaultCalls { let codegen_results: CodegenResults = json::decode(&rlink_data).unwrap_or_else(|err| { sess.fatal(&format!("failed to decode rlink: {}", err)); }); - compiler.codegen_backend().link(&sess, Box::new(codegen_results), &outputs) + compiler.codegen_backend().link(&sess, codegen_results, &outputs) } else { sess.fatal("rlink must be a file") } @@ -627,7 +670,7 @@ impl RustcDefaultCalls { Input::File(ref ifile) => { let path = &(*ifile); let mut v = Vec::new(); - locator::list_file_metadata(&sess.target.target, path, metadata_loader, &mut v) + locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v) .unwrap(); println!("{}", String::from_utf8(v).unwrap()); } @@ -681,7 +724,7 @@ impl RustcDefaultCalls { "{}", sess.target_tlib_path.as_ref().unwrap_or(&sess.host_tlib_path).dir.display() ), - TargetSpec => println!("{}", sess.target.target.to_json().pretty()), + TargetSpec => println!("{}", sess.target.to_json().pretty()), FileNames | CrateName => { let input = input.unwrap_or_else(|| { early_error(ErrorOutputType::default(), "no input file provided") @@ -1215,9 +1258,9 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").map(|x| &x != "0").unwrap_or(false); - if backtrace { - TyCtxt::try_print_query_stack(&handler); - } + let num_frames = if backtrace { None } else { Some(2) }; + + TyCtxt::try_print_query_stack(&handler, num_frames); #[cfg(windows)] unsafe { @@ -1285,7 +1328,7 @@ pub fn main() -> ! { }) }) .collect::<Vec<_>>(); - run_compiler(&args, &mut callbacks, None, None, None) + RunCompiler::new(&args, &mut callbacks).run() }); // The extra `\t` is necessary to align this label with the others. print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed()); diff --git a/compiler/rustc_error_codes/src/error_codes/E0007.md b/compiler/rustc_error_codes/src/error_codes/E0007.md index 2be7870d5ae..2c22b86af92 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0007.md +++ b/compiler/rustc_error_codes/src/error_codes/E0007.md @@ -1,3 +1,5 @@ +#### Note: this error code is no longer emitted by the compiler. + This error indicates that the bindings in a match arm would require a value to be moved into more than one location, thus violating unique ownership. Code like the following is invalid as it requires the entire `Option<String>` to be @@ -6,11 +8,13 @@ inner `String` to be moved into a variable called `s`. Erroneous code example: -```compile_fail,E0007 +```compile_fail,E0382 +#![feature(bindings_after_at)] + let x = Some("s".to_string()); match x { - op_string @ Some(s) => {}, // error: cannot bind by-move with sub-bindings + op_string @ Some(s) => {}, // error: use of moved value None => {}, } ``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0424.md b/compiler/rustc_error_codes/src/error_codes/E0424.md index a9f6f579b42..a58c16b59e9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0424.md +++ b/compiler/rustc_error_codes/src/error_codes/E0424.md @@ -21,7 +21,7 @@ impl Foo { The `self` keyword can only be used inside methods, which are associated functions (functions defined inside of a `trait` or `impl` block) that have a `self` receiver as its first parameter, like `self`, `&self`, `&mut self` or -`self: &mut Pin<Self>` (this last one is an example of an ["abitrary `self` +`self: &mut Pin<Self>` (this last one is an example of an ["arbitrary `self` type"](https://github.com/rust-lang/rust/issues/44874)). Check if the associated function's parameter list should have contained a `self` diff --git a/compiler/rustc_error_codes/src/error_codes/E0660.md b/compiler/rustc_error_codes/src/error_codes/E0660.md index fccd1b96f60..26d35f2620c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0660.md +++ b/compiler/rustc_error_codes/src/error_codes/E0660.md @@ -9,4 +9,4 @@ llvm_asm!("nop" "nop"); Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0661.md b/compiler/rustc_error_codes/src/error_codes/E0661.md index f1debee7a18..0b8ba7fbbed 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0661.md +++ b/compiler/rustc_error_codes/src/error_codes/E0661.md @@ -10,4 +10,4 @@ llvm_asm!("nop" : "r"(a)); Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0662.md b/compiler/rustc_error_codes/src/error_codes/E0662.md index d4765f078b0..8c1bab8d041 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0662.md +++ b/compiler/rustc_error_codes/src/error_codes/E0662.md @@ -13,4 +13,4 @@ llvm_asm!("xor %eax, %eax" Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0663.md b/compiler/rustc_error_codes/src/error_codes/E0663.md index d5a85b275db..53ffd3373a5 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0663.md +++ b/compiler/rustc_error_codes/src/error_codes/E0663.md @@ -13,4 +13,4 @@ llvm_asm!("xor %eax, %eax" Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0664.md b/compiler/rustc_error_codes/src/error_codes/E0664.md index ce9c9491df3..f8e72cd330a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0664.md +++ b/compiler/rustc_error_codes/src/error_codes/E0664.md @@ -13,4 +13,4 @@ llvm_asm!("mov $$0x200, %eax" Considering that this would be a long explanation, we instead recommend you take a look at the [`llvm_asm`] chapter of the Unstable book: -[llvm_asm]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html +[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 870f7b81e21..91bfc6296b1 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -121,11 +121,6 @@ impl Diagnostic { self.level == Level::Cancelled } - /// Set the sorting span. - pub fn set_sort_span(&mut self, sp: Span) { - self.sort_span = sp; - } - /// Adds a span/label to be included in the resulting snippet. /// /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic @@ -535,14 +530,6 @@ impl Diagnostic { &self.message } - /// Used by a lint. Copies over all details *but* the "main - /// message". - pub fn copy_details_not_message(&mut self, from: &Diagnostic) { - self.span = from.span.clone(); - self.code = from.code.clone(); - self.children.extend(from.children.iter().cloned()) - } - /// Convenience function for internal use, clients should use one of the /// public methods above. pub fn sub( diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 98cbf98df92..b5155f8e910 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -510,8 +510,6 @@ impl Emitter for SilentEmitter { fn emit_diagnostic(&mut self, _: &Diagnostic) {} } -/// Maximum number of lines we will print for each error; arbitrary. -pub const MAX_HIGHLIGHT_LINES: usize = 6; /// Maximum number of lines we will print for a multiline suggestion; arbitrary. /// /// This should be replaced with a more involved mechanism to output multiline suggestions that diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index f7651ca0ba6..b0e43a260e9 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -148,17 +148,6 @@ impl Annotatable { } } - pub fn map_item_or<F, G>(self, mut f: F, mut or: G) -> Annotatable - where - F: FnMut(P<ast::Item>) -> P<ast::Item>, - G: FnMut(Annotatable) -> Annotatable, - { - match self { - Annotatable::Item(i) => Annotatable::Item(f(i)), - _ => or(self), - } - } - pub fn expect_trait_item(self) -> P<ast::AssocItem> { match self { Annotatable::TraitItem(i) => i, @@ -1052,9 +1041,6 @@ impl<'a> ExtCtxt<'a> { .chain(components.iter().map(|&s| Ident::with_dummy_span(s))) .collect() } - pub fn name_of(&self, st: &str) -> Symbol { - Symbol::intern(st) - } pub fn check_unused_macros(&mut self) { self.resolver.check_unused_macros(); diff --git a/compiler/rustc_expand/src/build.rs b/compiler/rustc_expand/src/build.rs index a5a7ee6c9a3..1c9bfb902d6 100644 --- a/compiler/rustc_expand/src/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -139,24 +139,6 @@ impl<'a> ExtCtxt<'a> { ast::Lifetime { id: ast::DUMMY_NODE_ID, ident: ident.with_span_pos(span) } } - pub fn lifetime_def( - &self, - span: Span, - ident: Ident, - attrs: Vec<ast::Attribute>, - bounds: ast::GenericBounds, - ) -> ast::GenericParam { - let lifetime = self.lifetime(span, ident); - ast::GenericParam { - ident: lifetime.ident, - id: lifetime.id, - attrs: attrs.into(), - bounds, - kind: ast::GenericParamKind::Lifetime, - is_placeholder: false, - } - } - pub fn stmt_expr(&self, expr: P<ast::Expr>) -> ast::Stmt { ast::Stmt { id: ast::DUMMY_NODE_ID, @@ -465,24 +447,6 @@ impl<'a> ExtCtxt<'a> { self.pat_tuple_struct(span, path, vec![pat]) } - pub fn pat_none(&self, span: Span) -> P<ast::Pat> { - let some = self.std_path(&[sym::option, sym::Option, sym::None]); - let path = self.path_global(span, some); - self.pat_path(span, path) - } - - pub fn pat_ok(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { - let some = self.std_path(&[sym::result, sym::Result, sym::Ok]); - let path = self.path_global(span, some); - self.pat_tuple_struct(span, path, vec![pat]) - } - - pub fn pat_err(&self, span: Span, pat: P<ast::Pat>) -> P<ast::Pat> { - let some = self.std_path(&[sym::result, sym::Result, sym::Err]); - let path = self.path_global(span, some); - self.pat_tuple_struct(span, path, vec![pat]) - } - pub fn arm(&self, span: Span, pat: P<ast::Pat>, expr: P<ast::Expr>) -> ast::Arm { ast::Arm { attrs: vec![], @@ -514,26 +478,6 @@ impl<'a> ExtCtxt<'a> { self.expr(span, ast::ExprKind::If(cond, self.block_expr(then), els)) } - pub fn lambda_fn_decl( - &self, - span: Span, - fn_decl: P<ast::FnDecl>, - body: P<ast::Expr>, - fn_decl_span: Span, - ) -> P<ast::Expr> { - self.expr( - span, - ast::ExprKind::Closure( - ast::CaptureBy::Ref, - ast::Async::No, - ast::Movability::Movable, - fn_decl, - body, - fn_decl_span, - ), - ) - } - pub fn lambda(&self, span: Span, ids: Vec<Ident>, body: P<ast::Expr>) -> P<ast::Expr> { let fn_decl = self.fn_decl( ids.iter().map(|id| self.param(span, *id, self.ty(span, ast::TyKind::Infer))).collect(), @@ -610,47 +554,6 @@ impl<'a> ExtCtxt<'a> { }) } - pub fn variant(&self, span: Span, ident: Ident, tys: Vec<P<ast::Ty>>) -> ast::Variant { - let vis_span = span.shrink_to_lo(); - let fields: Vec<_> = tys - .into_iter() - .map(|ty| ast::StructField { - span: ty.span, - ty, - ident: None, - vis: ast::Visibility { - span: vis_span, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - attrs: Vec::new(), - id: ast::DUMMY_NODE_ID, - is_placeholder: false, - }) - .collect(); - - let vdata = if fields.is_empty() { - ast::VariantData::Unit(ast::DUMMY_NODE_ID) - } else { - ast::VariantData::Tuple(fields, ast::DUMMY_NODE_ID) - }; - - ast::Variant { - attrs: Vec::new(), - data: vdata, - disr_expr: None, - id: ast::DUMMY_NODE_ID, - ident, - vis: ast::Visibility { - span: vis_span, - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - span, - is_placeholder: false, - } - } - pub fn item_static( &self, span: Span, diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index e2492efb9d7..4401ec0a04e 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -270,6 +270,9 @@ declare_features! ( (accepted, track_caller, "1.46.0", Some(47809), None), /// Allows `#[doc(alias = "...")]`. (accepted, doc_alias, "1.48.0", Some(50146), None), + /// Allows patterns with concurrent by-move and by-ref bindings. + /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. + (accepted, move_ref_pattern, "1.48.0", Some(68354), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 8a7f0517e73..7fbd070a609 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -526,10 +526,6 @@ declare_features! ( /// For example, you can write `x @ Some(y)`. (active, bindings_after_at, "1.41.0", Some(65490), None), - /// Allows patterns with concurrent by-move and by-ref bindings. - /// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref. - (active, move_ref_pattern, "1.42.0", Some(68354), None), - /// Allows `impl const Trait for T` syntax. (active, const_trait_impl, "1.42.0", Some(67792), None), diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 289b9f30c3b..7742961e65d 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -75,33 +75,6 @@ pub fn link_or_copy<P: AsRef<Path>, Q: AsRef<Path>>(p: P, q: Q) -> io::Result<Li } } -#[derive(Debug)] -pub enum RenameOrCopyRemove { - Rename, - CopyRemove, -} - -/// Rename `p` into `q`, preferring to use `rename` if possible. -/// If `rename` fails (rename may fail for reasons such as crossing -/// filesystem), fallback to copy & remove -pub fn rename_or_copy_remove<P: AsRef<Path>, Q: AsRef<Path>>( - p: P, - q: Q, -) -> io::Result<RenameOrCopyRemove> { - let p = p.as_ref(); - let q = q.as_ref(); - match fs::rename(p, q) { - Ok(()) => Ok(RenameOrCopyRemove::Rename), - Err(_) => match fs::copy(p, q) { - Ok(_) => { - fs::remove_file(p)?; - Ok(RenameOrCopyRemove::CopyRemove) - } - Err(e) => Err(e), - }, - } -} - #[cfg(unix)] pub fn path_to_c_string(p: &Path) -> CString { use std::ffi::OsStr; diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index afefde07f92..3f109376a3e 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -118,7 +118,7 @@ impl DefKey { let DisambiguatedDefPathData { ref data, disambiguator } = self.disambiguated_data; - ::std::mem::discriminant(data).hash(&mut hasher); + std::mem::discriminant(data).hash(&mut hasher); if let Some(name) = data.get_opt_name() { // Get a stable hash by considering the symbol chars rather than // the symbol index. @@ -188,10 +188,6 @@ pub struct DefPath { } impl DefPath { - pub fn is_local(&self) -> bool { - self.krate == LOCAL_CRATE - } - pub fn make<FN>(krate: CrateNum, start_index: DefIndex, mut get_key: FN) -> DefPath where FN: FnMut(DefIndex) -> DefKey, diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 636f67a77c8..52727e3a619 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3,7 +3,6 @@ use crate::def_id::DefId; crate use crate::hir_id::HirId; use crate::{itemlikevisit, LangItem}; -use rustc_ast::node_id::NodeMap; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect}; use rustc_ast::{AttrVec, Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, UintTy}; @@ -306,10 +305,6 @@ impl GenericArgs<'_> { Self { args: &[], bindings: &[], parenthesized: false } } - pub fn is_empty(&self) -> bool { - self.args.is_empty() && self.bindings.is_empty() && !self.parenthesized - } - pub fn inputs(&self) -> &[Ty<'_>] { if self.parenthesized { for arg in self.args { @@ -467,23 +462,6 @@ impl Generics<'hir> { } } - pub fn own_counts(&self) -> GenericParamCount { - // We could cache this as a property of `GenericParamCount`, but - // the aim is to refactor this away entirely eventually and the - // presence of this method will be a constant reminder. - let mut own_counts: GenericParamCount = Default::default(); - - for param in self.params { - match param.kind { - GenericParamKind::Lifetime { .. } => own_counts.lifetimes += 1, - GenericParamKind::Type { .. } => own_counts.types += 1, - GenericParamKind::Const { .. } => own_counts.consts += 1, - }; - } - - own_counts - } - pub fn get_named(&self, name: Symbol) -> Option<&GenericParam<'_>> { for param in self.params { if name == param.name.ident().name { @@ -2679,8 +2657,6 @@ pub struct Upvar { pub span: Span, } -pub type CaptureModeMap = NodeMap<CaptureBy>; - // The TraitCandidate's import_ids is empty if the trait is defined in the same module, and // has length > 0 if the trait is found through an chain of imports, starting with the // import/use statement in the scope where the trait is used. diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs index fea850c12d9..cc8ac4cf5be 100644 --- a/compiler/rustc_hir/src/hir_id.rs +++ b/compiler/rustc_hir/src/hir_id.rs @@ -45,5 +45,3 @@ pub const CRATE_HIR_ID: HirId = HirId { owner: LocalDefId { local_def_index: CRATE_DEF_INDEX }, local_id: ItemLocalId::from_u32(0), }; - -pub const DUMMY_ITEM_LOCAL_ID: ItemLocalId = ItemLocalId::MAX; diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs index 2f1b5da8e13..c05d3e44423 100644 --- a/compiler/rustc_hir/src/pat_util.rs +++ b/compiler/rustc_hir/src/pat_util.rs @@ -58,25 +58,6 @@ impl<T: ExactSizeIterator> EnumerateAndAdjustIterator for T { } impl hir::Pat<'_> { - pub fn is_refutable(&self) -> bool { - match self.kind { - PatKind::Lit(_) - | PatKind::Range(..) - | PatKind::Path(hir::QPath::Resolved(Some(..), _) | hir::QPath::TypeRelative(..)) => { - true - } - - PatKind::Path(hir::QPath::Resolved(_, ref path)) - | PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) - | PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => match path.res { - Res::Def(DefKind::Variant, _) => true, - _ => false, - }, - PatKind::Slice(..) => true, - _ => false, - } - } - /// Call `f` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, Ident)) { @@ -117,15 +98,6 @@ impl hir::Pat<'_> { }) } - /// Checks if the pattern contains any patterns that bind something to - /// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`, - pub fn contains_bindings_or_wild(&self) -> bool { - self.satisfies(|p| match p.kind { - PatKind::Binding(..) | PatKind::Wild => true, - _ => false, - }) - } - /// Checks if the pattern satisfies the given predicate on some sub-pattern. fn satisfies(&self, pred: impl Fn(&hir::Pat<'_>) -> bool) -> bool { let mut satisfies = false; diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index f6e4b1fb418..57a38adc169 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -44,9 +44,6 @@ pub trait PpAnn { fn nested(&self, _state: &mut State<'_>, _nested: Nested) {} fn pre(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {} fn post(&self, _state: &mut State<'_>, _node: AnnNode<'_>) {} - fn try_fetch_item(&self, _: hir::HirId) -> Option<&hir::Item<'_>> { - None - } } pub struct NoAnn; @@ -54,9 +51,6 @@ impl PpAnn for NoAnn {} pub const NO_ANN: &dyn PpAnn = &NoAnn; impl PpAnn for hir::Crate<'_> { - fn try_fetch_item(&self, item: hir::HirId) -> Option<&hir::Item<'_>> { - Some(self.item(item)) - } fn nested(&self, state: &mut State<'_>, nested: Nested) { match nested { Nested::Item(id) => state.print_item(self.item(id.id)), @@ -141,6 +135,9 @@ impl std::ops::DerefMut for State<'_> { } impl<'a> PrintState<'a> for State<'a> { + fn insert_extra_parens(&self) -> bool { + true + } fn comments(&mut self) -> &mut Option<Comments<'a>> { &mut self.comments } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9742f5e2346..ff7bbf0562f 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -113,13 +113,6 @@ impl Default for RegionckMode { } impl RegionckMode { - pub fn suppressed(self) -> bool { - match self { - Self::Solve => false, - Self::Erase { suppress_errors } => suppress_errors, - } - } - /// Indicates that the MIR borrowck will repeat these region /// checks, so we should ignore errors if NLL is (unconditionally) /// enabled. @@ -420,15 +413,6 @@ pub enum SubregionOrigin<'tcx> { #[cfg(target_arch = "x86_64")] static_assert_size!(SubregionOrigin<'_>, 32); -/// Places that type/region parameters can appear. -#[derive(Clone, Copy, Debug)] -pub enum ParameterOrigin { - Path, // foo::bar - MethodCall, // foo.bar() <-- parameters on impl providing bar() - OverloadedOperator, // a + b when overloaded - OverloadedDeref, // *a when overloaded -} - /// Times when we replace late-bound regions with variables: #[derive(Clone, Copy, Debug)] pub enum LateBoundRegionConversionTime { @@ -508,21 +492,6 @@ pub enum NLLRegionVariableOrigin { }, } -impl NLLRegionVariableOrigin { - pub fn is_universal(self) -> bool { - match self { - NLLRegionVariableOrigin::FreeRegion => true, - NLLRegionVariableOrigin::Placeholder(..) => true, - NLLRegionVariableOrigin::Existential { .. } => false, - NLLRegionVariableOrigin::RootEmptyRegion => false, - } - } - - pub fn is_existential(self) -> bool { - !self.is_universal() - } -} - // FIXME(eddyb) investigate overlap between this and `TyOrConstInferVar`. #[derive(Copy, Clone, Debug)] pub enum FixupError<'tcx> { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 839891f322c..2fb9f638e36 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -28,7 +28,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::{TypeFoldable, TypeVisitor}; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::subst::GenericArg; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use std::fmt::Debug; @@ -119,12 +118,6 @@ pub trait TypeRelatingDelegate<'tcx> { fn forbid_inference_vars() -> bool; } -#[derive(Clone, Debug)] -struct ScopesAndKind<'tcx> { - scopes: Vec<BoundRegionScope<'tcx>>, - kind: GenericArg<'tcx>, -} - #[derive(Clone, Debug, Default)] struct BoundRegionScope<'tcx> { map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>, @@ -341,7 +334,7 @@ where // been fully instantiated and hence the set of scopes we have // doesn't matter -- just to be sure, put an empty vector // in there. - let old_a_scopes = ::std::mem::take(pair.vid_scopes(self)); + let old_a_scopes = std::mem::take(pair.vid_scopes(self)); // Relate the generalized kind to the original one. let result = pair.relate_generalized_ty(self, generalized_ty); @@ -680,7 +673,7 @@ where // itself occurs. Note that `'b` and `'c` must both // include P. At the point, the call works because of // subtyping (i.e., `&'b u32 <: &{P} u32`). - let variance = ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); + let variance = std::mem::replace(&mut self.ambient_variance, ty::Variance::Covariant); self.relate(a.skip_binder(), b.skip_binder())?; @@ -709,7 +702,7 @@ where // Reset ambient variance to contravariance. See the // covariant case above for an explanation. let variance = - ::std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); + std::mem::replace(&mut self.ambient_variance, ty::Variance::Contravariant); self.relate(a.skip_binder(), b.skip_binder())?; diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 2851da89ab2..eb1a7806256 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -110,7 +110,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { /// Trait queries just want to pass back type obligations "as is" pub fn take_registered_region_obligations(&self) -> Vec<(hir::HirId, RegionObligation<'tcx>)> { - ::std::mem::take(&mut self.inner.borrow_mut().region_obligations) + std::mem::take(&mut self.inner.borrow_mut().region_obligations) } /// Process the region obligations that must be proven (during diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index a3c4920fa8a..aaf5e958c26 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -59,9 +59,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; #[cfg(target_arch = "x86_64")] static_assert_size!(PredicateObligation<'_>, 32); -pub type Obligations<'tcx, O> = Vec<Obligation<'tcx, O>>; pub type PredicateObligations<'tcx> = Vec<PredicateObligation<'tcx>>; -pub type TraitObligations<'tcx> = Vec<TraitObligation<'tcx>>; pub type Selection<'tcx> = ImplSource<'tcx, PredicateObligation<'tcx>>; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 66d3765d347..d9c24cc3994 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -551,6 +551,10 @@ fn write_out_deps( .map(|fmap| escape_dep_filename(&fmap.unmapped_path.as_ref().unwrap_or(&fmap.name))) .collect(); + if let Some(ref backend) = sess.opts.debugging_opts.codegen_backend { + files.push(backend.to_string()); + } + if sess.binary_dep_depinfo() { boxed_resolver.borrow().borrow_mut().access(|resolver| { for cnum in resolver.cstore().crates_untracked() { diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 8b82217a91a..1de7350a3e2 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -3,6 +3,7 @@ use crate::passes::{self, BoxedResolver, QueryContext}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; +use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal}; use rustc_errors::ErrorReported; use rustc_hir::def_id::LOCAL_CRATE; @@ -13,7 +14,8 @@ use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::steal::Steal; use rustc_middle::ty::{GlobalCtxt, ResolverOutputs, TyCtxt}; -use rustc_session::config::{OutputFilenames, OutputType}; +use rustc_serialize::json; +use rustc_session::config::{self, OutputFilenames, OutputType}; use rustc_session::{output::find_crate_name, Session}; use rustc_span::symbol::sym; use std::any::Any; @@ -331,6 +333,7 @@ impl<'tcx> Queries<'tcx> { pub fn linker(&'tcx self) -> Result<Linker> { let dep_graph = self.dep_graph()?; let prepare_outputs = self.prepare_outputs()?; + let crate_hash = self.global_ctxt()?.peek_mut().enter(|tcx| tcx.crate_hash(LOCAL_CRATE)); let ongoing_codegen = self.ongoing_codegen()?; let sess = self.session().clone(); @@ -340,6 +343,7 @@ impl<'tcx> Queries<'tcx> { sess, dep_graph: dep_graph.peek().clone(), prepare_outputs: prepare_outputs.take(), + crate_hash, ongoing_codegen: ongoing_codegen.take(), codegen_backend, }) @@ -350,18 +354,31 @@ pub struct Linker { sess: Lrc<Session>, dep_graph: DepGraph, prepare_outputs: OutputFilenames, + crate_hash: Svh, ongoing_codegen: Box<dyn Any>, codegen_backend: Lrc<Box<dyn CodegenBackend>>, } impl Linker { pub fn link(self) -> Result<()> { - let codegen_results = - self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess, &self.dep_graph)?; - let prof = self.sess.prof.clone(); + let (codegen_results, work_products) = + self.codegen_backend.join_codegen(self.ongoing_codegen, &self.sess)?; + + self.sess.compile_status()?; + + let sess = &self.sess; let dep_graph = self.dep_graph; + sess.time("serialize_work_products", || { + rustc_incremental::save_work_product_index(&sess, &dep_graph, work_products) + }); + + let prof = self.sess.prof.clone(); prof.generic_activity("drop_dep_graph").run(move || drop(dep_graph)); + // Now that we won't touch anything in the incremental compilation directory + // any more, we can finalize it (which involves renaming it) + rustc_incremental::finalize_session_directory(&self.sess, self.crate_hash); + if !self .sess .opts @@ -371,6 +388,19 @@ impl Linker { { return Ok(()); } + + if sess.opts.debugging_opts.no_link { + // FIXME: use a binary format to encode the `.rlink` file + let rlink_data = json::encode(&codegen_results).map_err(|err| { + sess.fatal(&format!("failed to encode rlink: {}", err)); + })?; + let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); + std::fs::write(&rlink_file, rlink_data).map_err(|err| { + sess.fatal(&format!("failed to write file {}: {}", rlink_file.display(), err)); + })?; + return Ok(()); + } + self.codegen_backend.link(&self.sess, codegen_results, &self.prepare_outputs) } } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 07ce9d0cd94..6553d0ecfdb 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -585,6 +585,7 @@ fn test_debugging_options_tracking_hash() { tracked!(symbol_mangling_version, SymbolManglingVersion::V0); tracked!(teach, true); tracked!(thinlto, Some(true)); + tracked!(tune_cpu, Some(String::from("abc"))); tracked!(tls_model, Some(TlsModel::GeneralDynamic)); tracked!(treat_err_as_bug, Some(1)); tracked!(unleash_the_miri_inside_of_you, true); diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index d784a86f14c..c5b59a041ab 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -48,6 +48,7 @@ impl Token { } /// Enum representing common lexeme types. +// perf note: Changing all `usize` to `u32` doesn't change performance. See #77629 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum TokenKind { // Multi-char tokens: @@ -160,6 +161,7 @@ pub enum LiteralKind { /// - `r##~"abcde"##`: `InvalidStarter` /// - `r###"abcde"##`: `NoTerminator { expected: 3, found: 2, possible_terminator_offset: Some(11)` /// - Too many `#`s (>65535): `TooManyDelimiters` +// perf note: It doesn't matter that this makes `Token` 36 bytes bigger. See #77629 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub enum RawStrError { /// Non `#` characters exist between `r` and `"` eg. `r#~"..` @@ -689,7 +691,12 @@ impl Cursor<'_> { let mut max_hashes = 0; // Count opening '#' symbols. - let n_start_hashes = self.eat_while(|c| c == '#'); + let mut eaten = 0; + while self.first() == '#' { + eaten += 1; + self.bump(); + } + let n_start_hashes = eaten; // Check that string is started. match self.bump() { @@ -724,16 +731,11 @@ impl Cursor<'_> { // Note that this will not consume extra trailing `#` characters: // `r###"abcde"####` is lexed as a `RawStr { n_hashes: 3 }` // followed by a `#` token. - let mut hashes_left = n_start_hashes; - let is_closing_hash = |c| { - if c == '#' && hashes_left != 0 { - hashes_left -= 1; - true - } else { - false - } - }; - let n_end_hashes = self.eat_while(is_closing_hash); + let mut n_end_hashes = 0; + while self.first() == '#' && n_end_hashes < n_start_hashes { + n_end_hashes += 1; + self.bump(); + } if n_end_hashes == n_start_hashes { return (n_start_hashes, None); @@ -807,17 +809,9 @@ impl Cursor<'_> { } /// Eats symbols while predicate returns true or until the end of file is reached. - /// Returns amount of eaten symbols. - fn eat_while<F>(&mut self, mut predicate: F) -> usize - where - F: FnMut(char) -> bool, - { - let mut eaten: usize = 0; + fn eat_while(&mut self, mut predicate: impl FnMut(char) -> bool) { while predicate(self.first()) && !self.is_eof() { - eaten += 1; self.bump(); } - - eaten } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index abd899e8db4..a7db9199665 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -2288,12 +2288,20 @@ impl EarlyLintPass for IncompleteFeatures { n, n, )); } + if HAS_MIN_FEATURES.contains(&name) { + builder.help(&format!( + "consider using `min_{}` instead, which is more stable and complete", + name, + )); + } builder.emit(); }) }); } } +const HAS_MIN_FEATURES: &[Symbol] = &[sym::const_generics, sym::specialization]; + declare_lint! { /// The `invalid_value` lint detects creating a value that is not valid, /// such as a NULL reference. diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 7a3035e5b46..48270eb59a0 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -711,10 +711,6 @@ impl<'tcx> LateContext<'tcx> { } } - pub fn current_lint_root(&self) -> hir::HirId { - self.last_node_with_lint_attrs - } - /// Check if a `DefId`'s path matches the given absolute type path usage. /// /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9925444b869..af14f28ff9f 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -304,7 +304,7 @@ fn lint_int_literal<'tcx>( t: ast::IntTy, v: u128, ) { - let int_type = t.normalize(cx.sess().target.ptr_width); + let int_type = t.normalize(cx.sess().target.pointer_width); let (min, max) = int_ty_range(int_type); let max = max as u128; let negative = type_limits.negated_expr_id == Some(e.hir_id); @@ -352,7 +352,7 @@ fn lint_uint_literal<'tcx>( lit: &hir::Lit, t: ast::UintTy, ) { - let uint_type = t.normalize(cx.sess().target.ptr_width); + let uint_type = t.normalize(cx.sess().target.pointer_width); let (min, max) = uint_ty_range(uint_type); let lit_val: u128 = match lit.node { // _v is u8, within range by definition diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 7b1c3f9ba2c..71ca4f23bbb 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1212,6 +1212,7 @@ struct LLVMRustThinLTOData { StringMap<FunctionImporter::ImportMapTy> ImportLists; StringMap<FunctionImporter::ExportSetTy> ExportLists; StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries; + StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {} }; @@ -1308,7 +1309,6 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, // // This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` with some of this // being lifted from `lib/LTO/LTO.cpp` as well - StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy; for (auto &I : Ret->Index) { if (I.second.SummaryList.size() > 1) @@ -1323,7 +1323,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, auto recordNewLinkage = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID, GlobalValue::LinkageTypes NewLinkage) { - ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; + Ret->ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; }; #if LLVM_VERSION_GE(9, 0) thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage, @@ -1491,7 +1491,7 @@ extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload // Calls `module_name_callback` for each module import done by ThinLTO. // The callback is provided with regular null-terminated C strings. extern "C" void -LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *data, +LLVMRustGetThinLTOModules(const LLVMRustThinLTOData *data, LLVMRustModuleNameCallback module_name_callback, void* callback_payload) { for (const auto& importing_module : data->ImportLists) { @@ -1653,3 +1653,36 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { MD->clearOperands(); MD->addOperand(Unit); } + +// Computes the LTO cache key for the provided 'ModId' in the given 'Data', +// storing the result in 'KeyOut'. +// Currently, this cache key is a SHA-1 hash of anything that could affect +// the result of optimizing this module (e.g. module imports, exports, liveness +// of access globals, etc). +// The precise details are determined by LLVM in `computeLTOCacheKey`, which is +// used during the normal linker-plugin incremental thin-LTO process. +extern "C" void +LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const char *ModId, LLVMRustThinLTOData *Data) { + SmallString<40> Key; + llvm::lto::Config conf; + const auto &ImportList = Data->ImportLists.lookup(ModId); + const auto &ExportList = Data->ExportLists.lookup(ModId); + const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId); + const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId); + std::set<GlobalValue::GUID> CfiFunctionDefs; + std::set<GlobalValue::GUID> CfiFunctionDecls; + + // Based on the 'InProcessThinBackend' constructor in LLVM + for (auto &Name : Data->Index.cfiFunctionDefs()) + CfiFunctionDefs.insert( + GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); + for (auto &Name : Data->Index.cfiFunctionDecls()) + CfiFunctionDecls.insert( + GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); + + llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId, + ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls + ); + + LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size()); +} diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs index f7454da90a3..44f57cfbe28 100644 --- a/compiler/rustc_metadata/src/dependency_format.rs +++ b/compiler/rustc_metadata/src/dependency_format.rs @@ -127,7 +127,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList { if ty == CrateType::Staticlib || (ty == CrateType::Executable && sess.crt_static(Some(ty)) - && !sess.target.target.options.crt_static_allows_dylibs) + && !sess.target.options.crt_static_allows_dylibs) { for &cnum in tcx.crates().iter() { if tcx.dep_kind(cnum).macros_only() { diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 0869ec28367..f225f8acc89 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -325,7 +325,7 @@ impl<'a> CrateLocator<'a> { hash, host_hash, extra_filename, - target: if is_host { &sess.host } else { &sess.target.target }, + target: if is_host { &sess.host } else { &sess.target }, triple: if is_host { TargetTriple::from_triple(config::host_triple()) } else { diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index e76c2cb356f..5e65f075ea4 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -149,7 +149,7 @@ impl Collector<'tcx> { } return; } - let is_osx = self.tcx.sess.target.target.options.is_like_osx; + let is_osx = self.tcx.sess.target.options.is_like_osx; if lib.kind == NativeLibKind::Framework && !is_osx { let msg = "native frameworks are only available on macOS targets"; match span { diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 2662f6b6ed6..b01a55b48da 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -313,27 +313,6 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { Ok(ty) } - fn cached_predicate_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<ty::Predicate<'tcx>, Self::Error> - where - F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>, - { - let tcx = self.tcx(); - - let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand }; - - if let Some(&pred) = tcx.pred_rcache.borrow().get(&key) { - return Ok(pred); - } - - let pred = or_insert_with(self)?; - tcx.pred_rcache.borrow_mut().insert(key, pred); - Ok(pred) - } - fn with_position<F, R>(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R, diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 60705f68681..05b8dad3097 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -94,7 +94,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, adt_def => { cdata.get_adt_def(def_id.index, tcx) } adt_destructor => { let _ = cdata; - tcx.calculate_dtor(def_id, &mut |_,_| Ok(())) + tcx.calculate_dtor(def_id, |_,_| Ok(())) } variances_of => { tcx.arena.alloc_from_iter(cdata.get_item_variances(def_id.index)) } associated_item_def_ids => { diff --git a/compiler/rustc_middle/src/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs index e3d4655831b..7aba4fc64a9 100644 --- a/compiler/rustc_middle/src/ich/impls_syntax.rs +++ b/compiler/rustc_middle/src/ich/impls_syntax.rs @@ -5,7 +5,7 @@ use crate::ich::StableHashingContext; use rustc_ast as ast; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_span::SourceFile; +use rustc_span::{BytePos, NormalizedPos, SourceFile}; use smallvec::SmallVec; @@ -102,22 +102,19 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile { } } -fn stable_byte_pos(pos: ::rustc_span::BytePos, source_file_start: ::rustc_span::BytePos) -> u32 { +fn stable_byte_pos(pos: BytePos, source_file_start: BytePos) -> u32 { pos.0 - source_file_start.0 } -fn stable_multibyte_char( - mbc: ::rustc_span::MultiByteChar, - source_file_start: ::rustc_span::BytePos, -) -> (u32, u32) { - let ::rustc_span::MultiByteChar { pos, bytes } = mbc; +fn stable_multibyte_char(mbc: rustc_span::MultiByteChar, source_file_start: BytePos) -> (u32, u32) { + let rustc_span::MultiByteChar { pos, bytes } = mbc; (pos.0 - source_file_start.0, bytes as u32) } fn stable_non_narrow_char( - swc: ::rustc_span::NonNarrowChar, - source_file_start: ::rustc_span::BytePos, + swc: rustc_span::NonNarrowChar, + source_file_start: BytePos, ) -> (u32, u32) { let pos = swc.pos(); let width = swc.width(); @@ -125,11 +122,8 @@ fn stable_non_narrow_char( (pos.0 - source_file_start.0, width as u32) } -fn stable_normalized_pos( - np: ::rustc_span::NormalizedPos, - source_file_start: ::rustc_span::BytePos, -) -> (u32, u32) { - let ::rustc_span::NormalizedPos { pos, diff } = np; +fn stable_normalized_pos(np: NormalizedPos, source_file_start: BytePos) -> (u32, u32) { + let NormalizedPos { pos, diff } = np; (pos.0 - source_file_start.0, diff) } diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 4756e83b5e9..254b57a005e 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -3,7 +3,6 @@ //! which are available for use externally when compiled as a library. use rustc_data_structures::fx::FxHashMap; -use rustc_hir::def_id::DefIdSet; use rustc_hir::HirId; use rustc_macros::HashStable; use std::fmt; @@ -59,7 +58,3 @@ impl<Id: Hash + Eq + fmt::Debug> fmt::Debug for AccessLevels<Id> { fmt::Debug::fmt(&self.map, f) } } - -/// A set containing all exported definitions from external crates. -/// The set does not contain any entries from local crates. -pub type ExternalExports = DefIdSet; diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs index 4c6ac820604..38cb3c1701f 100644 --- a/compiler/rustc_middle/src/middle/region.rs +++ b/compiler/rustc_middle/src/middle/region.rs @@ -283,23 +283,27 @@ pub struct ScopeTree { /// To see that this method works, consider: /// /// Let `D` be our binding/temporary and `U` be our other HIR node, with - /// `HIR-postorder(U) < HIR-postorder(D)` (in our example, U would be - /// the yield and D would be one of the calls). Let's show that - /// `D` is storage-dead at `U`. + /// `HIR-postorder(U) < HIR-postorder(D)`. Suppose, as in our example, + /// U is the yield and D is one of the calls. + /// Let's show that `D` is storage-dead at `U`. /// /// Remember that storage-live/storage-dead refers to the state of /// the *storage*, and does not consider moves/drop flags. /// /// Then: + /// /// 1. From the ordering guarantee of HIR visitors (see /// `rustc_hir::intravisit`), `D` does not dominate `U`. + /// /// 2. Therefore, `D` is *potentially* storage-dead at `U` (because /// we might visit `U` without ever getting to `D`). + /// /// 3. However, we guarantee that at each HIR point, each /// binding/temporary is always either always storage-live /// or always storage-dead. This is what is being guaranteed /// by `terminating_scopes` including all blocks where the /// count of executions is not guaranteed. + /// /// 4. By `2.` and `3.`, `D` is *statically* storage-dead at `U`, /// QED. /// diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index ee1ea816e01..5ebe38b2d7e 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -40,7 +40,7 @@ pub struct Allocation<Tag = (), Extra = ()> { pub extra: Extra, } -pub trait AllocationExtra<Tag>: ::std::fmt::Debug + Clone { +pub trait AllocationExtra<Tag>: std::fmt::Debug + Clone { // There is no constructor in here because the constructor's type depends // on `MemoryKind`, and making things sufficiently generic leads to painful // inference failure. diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 3751249853f..cb8782ce817 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -56,15 +56,6 @@ impl<'tcx> ConstValue<'tcx> { } } - pub fn try_to_str_slice(&self) -> Option<&'tcx str> { - if let ConstValue::Slice { data, start, end } = *self { - ::std::str::from_utf8(data.inspect_with_uninit_and_ptr_outside_interpreter(start..end)) - .ok() - } else { - None - } - } - pub fn try_to_bits(&self, size: Size) -> Option<u128> { self.try_to_scalar()?.to_bits(size).ok() } @@ -465,7 +456,7 @@ impl<'tcx, Tag> Scalar<Tag> { pub fn to_char(self) -> InterpResult<'tcx, char> { let val = self.to_u32()?; - match ::std::char::from_u32(val) { + match std::char::from_u32(val) { Some(c) => Ok(c), None => throw_ub!(InvalidChar(val)), } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 92a2baa30ee..16472c78757 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -3,7 +3,7 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html use crate::mir::coverage::{CodeRegion, CoverageKind}; -use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar}; +use crate::mir::interpret::{Allocation, GlobalAlloc, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; use crate::ty::codec::{TyDecoder, TyEncoder}; @@ -460,17 +460,6 @@ impl<'tcx> Body<'tcx> { } } - /// Checks if `sub` is a sub scope of `sup` - pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool { - while sub != sup { - match self.source_scopes[sub].parent_scope { - None => return false, - Some(p) => sub = p, - } - } - true - } - /// Returns the return type; it always return first element from `local_decls` array. #[inline] pub fn return_ty(&self) -> Ty<'tcx> { @@ -775,7 +764,7 @@ mod binding_form_impl { impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for super::BindingForm<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { use super::BindingForm::*; - ::std::mem::discriminant(self).hash_stable(hcx, hasher); + std::mem::discriminant(self).hash_stable(hcx, hasher); match self { Var(binding) => binding.hash_stable(hcx, hasher), @@ -1978,45 +1967,6 @@ impl<'tcx> Operand<'tcx> { }) } - /// Convenience helper to make a `Scalar` from the given `Operand`, assuming that `Operand` - /// wraps a constant literal value. Panics if this is not the case. - pub fn scalar_from_const(operand: &Operand<'tcx>) -> Scalar { - match operand { - Operand::Constant(constant) => match constant.literal.val.try_to_scalar() { - Some(scalar) => scalar, - _ => panic!("{:?}: Scalar value expected", constant.literal.val), - }, - _ => panic!("{:?}: Constant expected", operand), - } - } - - /// Convenience helper to make a literal-like constant from a given `&str` slice. - /// Since this is used to synthesize MIR, assumes `user_ty` is None. - pub fn const_from_str(tcx: TyCtxt<'tcx>, val: &str, span: Span) -> Operand<'tcx> { - let tcx = tcx; - let allocation = Allocation::from_byte_aligned_bytes(val.as_bytes()); - let allocation = tcx.intern_const_alloc(allocation); - let const_val = ConstValue::Slice { data: allocation, start: 0, end: val.len() }; - let ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.types.str_); - Operand::Constant(box Constant { - span, - user_ty: None, - literal: ty::Const::from_value(tcx, const_val, ty), - }) - } - - /// Convenience helper to make a `ConstValue` from the given `Operand`, assuming that `Operand` - /// wraps a constant value (such as a `&str` slice). Panics if this is not the case. - pub fn value_from_const(operand: &Operand<'tcx>) -> ConstValue<'tcx> { - match operand { - Operand::Constant(constant) => match constant.literal.val.try_to_value() { - Some(const_value) => const_value, - _ => panic!("{:?}: ConstValue expected", constant.literal.val), - }, - _ => panic!("{:?}: Constant expected", operand), - } - } - pub fn to_copy(&self) -> Self { match *self { Operand::Copy(_) | Operand::Constant(_) => self.clone(), @@ -2413,10 +2363,6 @@ impl<'tcx> UserTypeProjections { self.contents.is_empty() } - pub fn from_projections(projs: impl Iterator<Item = (UserTypeProjection, Span)>) -> Self { - UserTypeProjections { contents: projs.collect() } - } - pub fn projections_and_spans( &self, ) -> impl Iterator<Item = &(UserTypeProjection, Span)> + ExactSizeIterator { diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 0878e9313d8..6022194342d 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -1,9 +1,10 @@ //! Values computed by queries that use MIR. -use crate::mir::{Body, Promoted}; +use crate::mir::{abstract_const, Body, Promoted}; use crate::ty::{self, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; +use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_index::bit_set::BitMatrix; @@ -407,18 +408,12 @@ pub struct CoverageInfo { pub num_expressions: u32, } +/// Shims which make dealing with `WithOptConstParam` easier. +/// +/// For more information on why this is needed, consider looking +/// at the docs for `WithOptConstParam` itself. impl<'tcx> TyCtxt<'tcx> { - pub fn mir_borrowck_opt_const_arg( - self, - def: ty::WithOptConstParam<LocalDefId>, - ) -> &'tcx BorrowCheckResult<'tcx> { - if let Some(param_did) = def.const_param_did { - self.mir_borrowck_const_arg((def.did, param_did)) - } else { - self.mir_borrowck(def.did) - } - } - + #[inline] pub fn mir_const_qualif_opt_const_arg( self, def: ty::WithOptConstParam<LocalDefId>, @@ -430,7 +425,8 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn promoted_mir_of_opt_const_arg( + #[inline] + pub fn promoted_mir_opt_const_arg( self, def: ty::WithOptConstParam<DefId>, ) -> &'tcx IndexVec<Promoted, Body<'tcx>> { @@ -440,4 +436,28 @@ impl<'tcx> TyCtxt<'tcx> { self.promoted_mir(def.did) } } + + #[inline] + pub fn optimized_mir_opt_const_arg( + self, + def: ty::WithOptConstParam<DefId>, + ) -> &'tcx Body<'tcx> { + if let Some((did, param_did)) = def.as_const_arg() { + self.optimized_mir_of_const_arg((did, param_did)) + } else { + self.optimized_mir(def.did) + } + } + + #[inline] + pub fn mir_abstract_const_opt_const_arg( + self, + def: ty::WithOptConstParam<DefId>, + ) -> Result<Option<&'tcx [abstract_const::Node<'tcx>]>, ErrorReported> { + if let Some((did, param_did)) = def.as_const_arg() { + self.mir_abstract_const_of_const_arg((did, param_did)) + } else { + self.mir_abstract_const(def.did) + } + } } diff --git a/compiler/rustc_middle/src/mir/terminator/mod.rs b/compiler/rustc_middle/src/mir/terminator/mod.rs index 8909f02270c..e1071454e65 100644 --- a/compiler/rustc_middle/src/mir/terminator/mod.rs +++ b/compiler/rustc_middle/src/mir/terminator/mod.rs @@ -1,6 +1,7 @@ use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use smallvec::{smallvec, SmallVec}; use super::{ AssertMessage, BasicBlock, InlineAsmOperand, Operand, Place, SourceInfo, Successors, @@ -16,6 +17,87 @@ use std::slice; pub use super::query::*; +#[derive(Debug, Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] +pub struct SwitchTargets { + /// Possible values. The locations to branch to in each case + /// are found in the corresponding indices from the `targets` vector. + values: SmallVec<[u128; 1]>, + + /// Possible branch sites. The last element of this vector is used + /// for the otherwise branch, so targets.len() == values.len() + 1 + /// should hold. + // + // This invariant is quite non-obvious and also could be improved. + // One way to make this invariant is to have something like this instead: + // + // branches: Vec<(ConstInt, BasicBlock)>, + // otherwise: Option<BasicBlock> // exhaustive if None + // + // However we’ve decided to keep this as-is until we figure a case + // where some other approach seems to be strictly better than other. + targets: SmallVec<[BasicBlock; 2]>, +} + +impl SwitchTargets { + /// Creates switch targets from an iterator of values and target blocks. + /// + /// The iterator may be empty, in which case the `SwitchInt` instruction is equivalent to + /// `goto otherwise;`. + pub fn new(targets: impl Iterator<Item = (u128, BasicBlock)>, otherwise: BasicBlock) -> Self { + let (values, mut targets): (SmallVec<_>, SmallVec<_>) = targets.unzip(); + targets.push(otherwise); + Self { values: values.into(), targets } + } + + /// Builds a switch targets definition that jumps to `then` if the tested value equals `value`, + /// and to `else_` if not. + pub fn static_if(value: u128, then: BasicBlock, else_: BasicBlock) -> Self { + Self { values: smallvec![value], targets: smallvec![then, else_] } + } + + /// Returns the fallback target that is jumped to when none of the values match the operand. + pub fn otherwise(&self) -> BasicBlock { + *self.targets.last().unwrap() + } + + /// Returns an iterator over the switch targets. + /// + /// The iterator will yield tuples containing the value and corresponding target to jump to, not + /// including the `otherwise` fallback target. + /// + /// Note that this may yield 0 elements. Only the `otherwise` branch is mandatory. + pub fn iter(&self) -> SwitchTargetsIter<'_> { + SwitchTargetsIter { inner: self.values.iter().zip(self.targets.iter()) } + } + + /// Returns a slice with all possible jump targets (including the fallback target). + pub fn all_targets(&self) -> &[BasicBlock] { + &self.targets + } + + pub fn all_targets_mut(&mut self) -> &mut [BasicBlock] { + &mut self.targets + } +} + +pub struct SwitchTargetsIter<'a> { + inner: iter::Zip<slice::Iter<'a, u128>, slice::Iter<'a, BasicBlock>>, +} + +impl<'a> Iterator for SwitchTargetsIter<'a> { + type Item = (u128, BasicBlock); + + fn next(&mut self) -> Option<Self::Item> { + self.inner.next().map(|(val, bb)| (*val, *bb)) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.inner.size_hint() + } +} + +impl<'a> ExactSizeIterator for SwitchTargetsIter<'a> {} + #[derive(Clone, TyEncodable, TyDecodable, HashStable, PartialEq)] pub enum TerminatorKind<'tcx> { /// Block should have one successor in the graph; we jump there. @@ -32,23 +114,7 @@ pub enum TerminatorKind<'tcx> { /// FIXME: remove this redundant information. Currently, it is relied on by pretty-printing. switch_ty: Ty<'tcx>, - /// Possible values. The locations to branch to in each case - /// are found in the corresponding indices from the `targets` vector. - values: Cow<'tcx, [u128]>, - - /// Possible branch sites. The last element of this vector is used - /// for the otherwise branch, so targets.len() == values.len() + 1 - /// should hold. - // - // This invariant is quite non-obvious and also could be improved. - // One way to make this invariant is to have something like this instead: - // - // branches: Vec<(ConstInt, BasicBlock)>, - // otherwise: Option<BasicBlock> // exhaustive if None - // - // However we’ve decided to keep this as-is until we figure a case - // where some other approach seems to be strictly better than other. - targets: Vec<BasicBlock>, + targets: SwitchTargets, }, /// Indicates that the landing pad is finished and unwinding should @@ -227,12 +293,10 @@ impl<'tcx> TerminatorKind<'tcx> { t: BasicBlock, f: BasicBlock, ) -> TerminatorKind<'tcx> { - static BOOL_SWITCH_FALSE: &[u128] = &[0]; TerminatorKind::SwitchInt { discr: cond, switch_ty: tcx.types.bool, - values: From::from(BOOL_SWITCH_FALSE), - targets: vec![f, t], + targets: SwitchTargets::static_if(0, f, t), } } @@ -263,7 +327,7 @@ impl<'tcx> TerminatorKind<'tcx> { | FalseUnwind { real_target: ref t, unwind: Some(ref u) } => { Some(t).into_iter().chain(slice::from_ref(u)) } - SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]), + SwitchInt { ref targets, .. } => None.into_iter().chain(&targets.targets[..]), FalseEdge { ref real_target, ref imaginary_target } => { Some(real_target).into_iter().chain(slice::from_ref(imaginary_target)) } @@ -297,7 +361,7 @@ impl<'tcx> TerminatorKind<'tcx> { | FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => { Some(t).into_iter().chain(slice::from_mut(u)) } - SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets[..]), + SwitchInt { ref mut targets, .. } => None.into_iter().chain(&mut targets.targets[..]), FalseEdge { ref mut real_target, ref mut imaginary_target } => { Some(real_target).into_iter().chain(slice::from_mut(imaginary_target)) } @@ -469,11 +533,12 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], - SwitchInt { ref values, switch_ty, .. } => ty::tls::with(|tcx| { + SwitchInt { ref targets, switch_ty, .. } => ty::tls::with(|tcx| { let param_env = ty::ParamEnv::empty(); let switch_ty = tcx.lift(&switch_ty).unwrap(); let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size; - values + targets + .values .iter() .map(|&u| { ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty) diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs index ad2eae0298c..9297aed66a4 100644 --- a/compiler/rustc_middle/src/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -21,10 +21,9 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { let kind = match self.kind { Goto { target } => Goto { target }, - SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { + SwitchInt { ref discr, switch_ty, ref targets } => SwitchInt { discr: discr.fold_with(folder), switch_ty: switch_ty.fold_with(folder), - values: values.clone(), targets: targets.clone(), }, Drop { ref place, target, unwind } => { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 9a6bfa10189..58dd0bc00d2 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -453,7 +453,6 @@ macro_rules! make_mir_visitor { TerminatorKind::SwitchInt { discr, switch_ty, - values: _, targets: _ } => { self.visit_operand(discr, location); @@ -1187,16 +1186,6 @@ impl PlaceContext { ) } - /// Returns `true` if this place context represents a storage live marker. - pub fn is_storage_live_marker(&self) -> bool { - matches!(self, PlaceContext::NonUse(NonUseContext::StorageLive)) - } - - /// Returns `true` if this place context represents a storage dead marker. - pub fn is_storage_dead_marker(&self) -> bool { - matches!(self, PlaceContext::NonUse(NonUseContext::StorageDead)) - } - /// Returns `true` if this place context represents a use that potentially changes the value. pub fn is_mutating_use(&self) -> bool { matches!(self, PlaceContext::MutatingUse(..)) diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index fc4c343372a..1acb44f6d22 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -92,7 +92,7 @@ rustc_queries! { /// Computes the `DefId` of the corresponding const parameter in case the `key` is a /// const argument and returns `None` otherwise. /// - /// ```rust + /// ```ignore (incomplete) /// let a = foo::<7>(); /// // ^ Calling `opt_const_param_of` for this argument, /// @@ -162,10 +162,12 @@ rustc_queries! { /// Specifically this is the bounds written on the trait's type /// definition, or those after the `impl` keyword /// + /// ```ignore (incomplete) /// type X: Bound + 'lt - /// ^^^^^^^^^^^ + /// // ^^^^^^^^^^^ /// impl Debug + Display - /// ^^^^^^^^^^^^^^^ + /// // ^^^^^^^^^^^^^^^ + /// ``` /// /// `key` is the `DefId` of the associated type or opaque type. /// @@ -176,18 +178,22 @@ rustc_queries! { /// Elaborated version of the predicates from `explicit_item_bounds`. /// - /// Example for + /// For example: /// + /// ``` /// trait MyTrait { - /// type MyAType: Eq + ?Sized` + /// type MyAType: Eq + ?Sized; /// } + /// ``` /// /// `explicit_item_bounds` returns `[<Self as MyTrait>::MyAType: Eq]`, /// and `item_bounds` returns + /// ```text /// [ /// <Self as Trait>::MyAType: Eq, /// <Self as Trait>::MyAType: PartialEq<<Self as Trait>::MyAType> /// ] + /// ``` /// /// Bounds from the parent (e.g. with nested impl trait) are not included. query item_bounds(key: DefId) -> &'tcx ty::List<ty::Predicate<'tcx>> { diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs index 8ea34f9161a..aaf6a857043 100644 --- a/compiler/rustc_middle/src/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -182,14 +182,6 @@ pub trait TyDecoder<'tcx>: Decoder { where F: FnOnce(&mut Self) -> Result<Ty<'tcx>, Self::Error>; - fn cached_predicate_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<ty::Predicate<'tcx>, Self::Error> - where - F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>; - fn with_position<F, R>(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e67a76f0111..e24ba6d7a1e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -534,10 +534,6 @@ impl<'tcx> TypeckResults<'tcx> { self.node_type(pat.hir_id) } - pub fn pat_ty_opt(&self, pat: &hir::Pat<'_>) -> Option<Ty<'tcx>> { - self.node_type_opt(pat.hir_id) - } - // Returns the type of an expression as a monotype. // // NB (1): This is the PRE-ADJUSTMENT TYPE for the expression. That is, in @@ -1083,7 +1079,7 @@ impl<'tcx> TyCtxt<'tcx> { crate_name: &str, output_filenames: &OutputFilenames, ) -> GlobalCtxt<'tcx> { - let data_layout = TargetDataLayout::parse(&s.target.target).unwrap_or_else(|err| { + let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| { s.fatal(&err); }); let interners = CtxtInterners::new(arena); @@ -1526,7 +1522,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Determines whether identifiers in the assembly have strict naming rules. /// Currently, only NVPTX* targets need it. pub fn has_strict_asm_symbol_naming(self) -> bool { - self.sess.target.target.arch.contains("nvptx") + self.sess.target.arch.contains("nvptx") } /// Returns `&'static core::panic::Location<'static>`. diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 84134bedef0..5524d91a6d5 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -97,9 +97,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn has_infer_types_or_consts(&self) -> bool { self.has_type_flags(TypeFlags::HAS_TY_INFER | TypeFlags::HAS_CT_INFER) } - fn has_infer_consts(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_CT_INFER) - } fn needs_infer(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_INFER) } @@ -113,9 +110,6 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn needs_subst(&self) -> bool { self.has_type_flags(TypeFlags::NEEDS_SUBST) } - fn has_re_placeholders(&self) -> bool { - self.has_type_flags(TypeFlags::HAS_RE_PLACEHOLDER) - } /// "Free" regions in this context means that it has any region /// that is not (a) erased or (b) late-bound. fn has_free_regions(&self) -> bool { @@ -719,21 +713,15 @@ impl<'tcx> TyCtxt<'tcx> { // vars. See comment on `shift_vars_through_binders` method in // `subst.rs` for more details. -enum Direction { - In, - Out, -} - struct Shifter<'tcx> { tcx: TyCtxt<'tcx>, current_index: ty::DebruijnIndex, amount: u32, - direction: Direction, } impl Shifter<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, amount: u32, direction: Direction) -> Self { - Shifter { tcx, current_index: ty::INNERMOST, amount, direction } + pub fn new(tcx: TyCtxt<'tcx>, amount: u32) -> Self { + Shifter { tcx, current_index: ty::INNERMOST, amount } } } @@ -755,13 +743,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { if self.amount == 0 || debruijn < self.current_index { r } else { - let debruijn = match self.direction { - Direction::In => debruijn.shifted_in(self.amount), - Direction::Out => { - assert!(debruijn.as_u32() >= self.amount); - debruijn.shifted_out(self.amount) - } - }; + let debruijn = debruijn.shifted_in(self.amount); let shifted = ty::ReLateBound(debruijn, br); self.tcx.mk_region(shifted) } @@ -776,13 +758,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { if self.amount == 0 || debruijn < self.current_index { ty } else { - let debruijn = match self.direction { - Direction::In => debruijn.shifted_in(self.amount), - Direction::Out => { - assert!(debruijn.as_u32() >= self.amount); - debruijn.shifted_out(self.amount) - } - }; + let debruijn = debruijn.shifted_in(self.amount); self.tcx.mk_ty(ty::Bound(debruijn, bound_ty)) } } @@ -796,13 +772,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { if self.amount == 0 || debruijn < self.current_index { ct } else { - let debruijn = match self.direction { - Direction::In => debruijn.shifted_in(self.amount), - Direction::Out => { - assert!(debruijn.as_u32() >= self.amount); - debruijn.shifted_out(self.amount) - } - }; + let debruijn = debruijn.shifted_in(self.amount); self.tcx.mk_const(ty::Const { val: ty::ConstKind::Bound(debruijn, bound_ct), ty }) } } else { @@ -830,16 +800,7 @@ where { debug!("shift_vars(value={:?}, amount={})", value, amount); - value.fold_with(&mut Shifter::new(tcx, amount, Direction::In)) -} - -pub fn shift_out_vars<'tcx, T>(tcx: TyCtxt<'tcx>, value: &T, amount: u32) -> T -where - T: TypeFoldable<'tcx>, -{ - debug!("shift_out_vars(value={:?}, amount={})", value, amount); - - value.fold_with(&mut Shifter::new(tcx, amount, Direction::Out)) + value.fold_with(&mut Shifter::new(tcx, amount)) } /// An "escaping var" is a bound var whose binder is not part of `t`. A bound var can be a diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 2c1179c21fb..bf1f5b81c9f 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -104,14 +104,6 @@ impl<'tcx> TyCtxt<'tcx> { // ``` ty.uninhabited_from(self, param_env).contains(self, module) } - - pub fn is_ty_uninhabited_from_any_module( - self, - ty: Ty<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> bool { - !ty.uninhabited_from(self, param_env).is_empty() - } } impl<'tcx> AdtDef { diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index f8e8c209d37..4a2c97b4a40 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -291,7 +291,17 @@ impl<'tcx> Instance<'tcx> { } pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { - Instance::new(def_id, tcx.empty_substs_for_def_id(def_id)) + let substs = InternalSubsts::for_item(tcx, def_id, |param, _| match param.kind { + ty::GenericParamDefKind::Lifetime => tcx.lifetimes.re_erased.into(), + ty::GenericParamDefKind::Type { .. } => { + bug!("Instance::mono: {:?} has type parameters", def_id) + } + ty::GenericParamDefKind::Const { .. } => { + bug!("Instance::mono: {:?} has const parameters", def_id) + } + }); + + Instance::new(def_id, substs) } #[inline] diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index f6f71d002a8..91c3dcbfa81 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -106,7 +106,7 @@ impl IntegerExt for Integer { } if repr.c() { - match &tcx.sess.target.target.arch[..] { + match &tcx.sess.target.arch[..] { // WARNING: the ARM EABI has two variants; the one corresponding // to `at_least == I32` appears to be used on Linux and NetBSD, // but some systems may use the variant corresponding to no @@ -1894,7 +1894,7 @@ impl<'tcx, T: HasTyCtxt<'tcx>> HasTyCtxt<'tcx> for LayoutCx<'tcx, T> { } } -pub type TyAndLayout<'tcx> = ::rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>; +pub type TyAndLayout<'tcx> = rustc_target::abi::TyAndLayout<'tcx, Ty<'tcx>>; impl<'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'tcx>> { type Ty = Ty<'tcx>; @@ -2548,7 +2548,7 @@ where let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); use rustc_target::spec::abi::Abi::*; - let conv = match cx.tcx().sess.target.target.adjust_abi(sig.abi) { + let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) { RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, // It's the ABI's job to select this, not ours. @@ -2600,7 +2600,7 @@ where extra_args.to_vec() }; - let target = &cx.tcx().sess.target.target; + let target = &cx.tcx().sess.target; let target_env_gnu_like = matches!(&target.target_env[..], "gnu" | "musl"); let win_x64_gnu = target.target_os == "windows" && target.arch == "x86_64" && target.target_env == "gnu"; @@ -2775,7 +2775,7 @@ where // anyway, we control all calls to it in libstd. Abi::Vector { .. } if abi != SpecAbi::PlatformIntrinsic - && cx.tcx().sess.target.target.options.simd_types_indirect => + && cx.tcx().sess.target.options.simd_types_indirect => { arg.make_indirect(); return; diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f069faed9e2..275888b0ce2 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -7,7 +7,6 @@ pub use self::Variance::*; use crate::hir::exports::ExportMap; use crate::ich::StableHashingContext; -use crate::infer::canonical::Canonical; use crate::middle::cstore::CrateStoreDyn; use crate::middle::resolve_lifetime::ObjectLifetimeDefault; use crate::mir::interpret::ErrorHandled; @@ -656,8 +655,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> { #[rustc_diagnostic_item = "Ty"] pub type Ty<'tcx> = &'tcx TyS<'tcx>; -pub type CanonicalTy<'tcx> = Canonical<'tcx, Ty<'tcx>>; - #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] pub struct UpvarPath { pub hir_id: hir::HirId, @@ -767,10 +764,6 @@ pub enum IntVarValue { pub struct FloatVarValue(pub ast::FloatTy); impl ty::EarlyBoundRegion { - pub fn to_bound_region(&self) -> ty::BoundRegion { - ty::BoundRegion::BrNamed(self.def_id, self.name) - } - /// Does this early bound region have a name? Early bound regions normally /// always have names except when using anonymous lifetimes (`'_`). pub fn has_name(&self) -> bool { @@ -821,14 +814,6 @@ impl GenericParamDef { bug!("cannot convert a non-lifetime parameter def to an early bound region") } } - - pub fn to_bound_region(&self) -> ty::BoundRegion { - if let GenericParamDefKind::Lifetime = self.kind { - self.to_early_bound_region_data().to_bound_region() - } else { - bug!("cannot convert a non-lifetime parameter def to an early bound region") - } - } } #[derive(Default)] @@ -1003,22 +988,6 @@ impl<'tcx> GenericPredicates<'tcx> { instantiated.predicates.extend(self.predicates.iter().map(|(p, _)| p)); instantiated.spans.extend(self.predicates.iter().map(|(_, s)| s)); } - - pub fn instantiate_supertrait( - &self, - tcx: TyCtxt<'tcx>, - poly_trait_ref: &ty::PolyTraitRef<'tcx>, - ) -> InstantiatedPredicates<'tcx> { - assert_eq!(self.parent, None); - InstantiatedPredicates { - predicates: self - .predicates - .iter() - .map(|(pred, _)| pred.subst_supertrait(tcx, poly_trait_ref)) - .collect(), - spans: self.predicates.iter().map(|(_, sp)| *sp).collect(), - } - } } #[derive(Debug)] @@ -1303,7 +1272,6 @@ impl<'tcx> PolyTraitPredicate<'tcx> { #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, TypeFoldable)] pub struct OutlivesPredicate<A, B>(pub A, pub B); // `A: B` -pub type PolyOutlivesPredicate<A, B> = ty::Binder<OutlivesPredicate<A, B>>; pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>; pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>; pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<RegionOutlivesPredicate<'tcx>>; @@ -2953,13 +2921,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair. pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { match instance { - ty::InstanceDef::Item(def) => { - if let Some((did, param_did)) = def.as_const_arg() { - self.optimized_mir_of_const_arg((did, param_did)) - } else { - self.optimized_mir(def.did) - } - } + ty::InstanceDef::Item(def) => self.optimized_mir_opt_const_arg(def), ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::Intrinsic(..) diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 48a62b64604..a594a8ad512 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -23,7 +23,7 @@ impl<'tcx> TyCtxt<'tcx> { { debug!( "normalize_erasing_regions::<{}>(value={:?}, param_env={:?})", - ::std::any::type_name::<T>(), + std::any::type_name::<T>(), value, param_env, ); diff --git a/compiler/rustc_middle/src/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs index 4c20141bbe6..86750d5c081 100644 --- a/compiler/rustc_middle/src/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -96,16 +96,14 @@ fn compute_components( } ty::Closure(_, ref substs) => { - for upvar_ty in substs.as_closure().upvar_tys() { - compute_components(tcx, upvar_ty, out, visited); - } + let tupled_ty = substs.as_closure().tupled_upvars_ty(); + compute_components(tcx, tupled_ty, out, visited); } ty::Generator(_, ref substs, _) => { // Same as the closure case - for upvar_ty in substs.as_generator().upvar_tys() { - compute_components(tcx, upvar_ty, out, visited); - } + let tupled_ty = substs.as_generator().tupled_upvars_ty(); + compute_components(tcx, tupled_ty, out, visited); // We ignore regions in the generator interior as we don't // want these to affect region inference diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index e1f02d0f704..08f88eed66f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -663,18 +663,13 @@ pub trait PrettyPrinter<'tcx>: } } else { p!(print_def_path(did, substs)); - if substs.as_generator().is_valid() { - // Search for the first inference variable - p!(" upvar_tys=("); - let mut uninferred_ty = - substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer()); - if uninferred_ty.next().is_some() { - p!(write("unavailable")); - } else { - self = self.comma_sep(substs.as_generator().upvar_tys())?; - } - p!(")"); + p!(" upvar_tys=("); + if !substs.as_generator().is_valid() { + p!("unavailable"); + } else { + self = self.comma_sep(substs.as_generator().upvar_tys())?; } + p!(")"); } if substs.as_generator().is_valid() { @@ -704,24 +699,17 @@ pub trait PrettyPrinter<'tcx>: } } else { p!(print_def_path(did, substs)); - if substs.as_closure().is_valid() { - // Search for the first inference variable - let mut uninferred_ty = - substs.as_closure().upvar_tys().filter(|ty| ty.is_ty_infer()); - if uninferred_ty.next().is_some() { - // If the upvar substs contain an inference variable we haven't - // finished capture analysis. - p!(" closure_substs=(unavailable)"); - } else { - p!(" closure_kind_ty=", print(substs.as_closure().kind_ty())); - p!( - " closure_sig_as_fn_ptr_ty=", - print(substs.as_closure().sig_as_fn_ptr_ty()) - ); - p!(" upvar_tys=("); - self = self.comma_sep(substs.as_closure().upvar_tys())?; - p!(")"); - } + if !substs.as_closure().is_valid() { + p!(" closure_substs=(unavailable)"); + } else { + p!(" closure_kind_ty=", print(substs.as_closure().kind_ty())); + p!( + " closure_sig_as_fn_ptr_ty=", + print(substs.as_closure().sig_as_fn_ptr_ty()) + ); + p!(" upvar_tys=("); + self = self.comma_sep(substs.as_closure().upvar_tys())?; + p!(")"); } } p!("]"); @@ -1142,7 +1130,7 @@ pub trait PrettyPrinter<'tcx>: // relocations (we have an active `str` reference here). We don't use this // result to affect interpreter execution. let slice = data.inspect_with_uninit_and_ptr_outside_interpreter(start..end); - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + let s = std::str::from_utf8(slice).expect("non utf8 str from miri"); p!(write("{:?}", s)); Ok(self) } diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index b0c48a860eb..173e9a31928 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -543,7 +543,7 @@ impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> { // tag matches and the correct amount of bytes was read. fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> Result<V, D::Error> where - T: Decodable<D> + Eq + ::std::fmt::Debug, + T: Decodable<D> + Eq + std::fmt::Debug, V: Decodable<D>, D: DecoderWithPosition, { @@ -601,29 +601,6 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { Ok(ty) } - fn cached_predicate_for_shorthand<F>( - &mut self, - shorthand: usize, - or_insert_with: F, - ) -> Result<ty::Predicate<'tcx>, Self::Error> - where - F: FnOnce(&mut Self) -> Result<ty::Predicate<'tcx>, Self::Error>, - { - let tcx = self.tcx(); - - let cache_key = - ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand }; - - if let Some(&pred) = tcx.pred_rcache.borrow().get(&cache_key) { - return Ok(pred); - } - - let pred = or_insert_with(self)?; - // This may overwrite the entry, but it should overwrite with the same value. - tcx.pred_rcache.borrow_mut().insert_same(cache_key, pred); - Ok(pred) - } - fn with_position<F, R>(&mut self, pos: usize, f: F) -> R where F: FnOnce(&mut Self) -> R, @@ -1023,7 +1000,7 @@ where let _timer = tcx .sess .prof - .extra_verbose_generic_activity("encode_query_results_for", ::std::any::type_name::<Q>()); + .extra_verbose_generic_activity("encode_query_results_for", std::any::type_name::<Q>()); let state = Q::query_state(tcx); assert!(state.all_inactive()); diff --git a/compiler/rustc_middle/src/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs index f3fa3634026..27bf22dac75 100644 --- a/compiler/rustc_middle/src/ty/query/plumbing.rs +++ b/compiler/rustc_middle/src/ty/query/plumbing.rs @@ -124,20 +124,23 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn try_print_query_stack(handler: &Handler) { + pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) { eprintln!("query stack during panic:"); // Be careful reyling on global state here: this code is called from // a panic hook, which means that the global `Handler` may be in a weird // state if it was responsible for triggering the panic. + let mut i = 0; ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { let query_map = icx.tcx.queries.try_collect_active_jobs(); let mut current_query = icx.query; - let mut i = 0; while let Some(query) = current_query { + if Some(i) == num_frames { + break; + } let query_info = if let Some(info) = query_map.as_ref().and_then(|map| map.get(&query)) { info @@ -163,7 +166,11 @@ impl<'tcx> TyCtxt<'tcx> { } }); - eprintln!("end of query stack"); + if num_frames == None || num_frames >= Some(i) { + eprintln!("end of query stack"); + } else { + eprintln!("we're just showing a limited slice of the query stack"); + } } } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 1af56972ad0..870cc4eee05 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -656,6 +656,14 @@ impl<'tcx> UpvarSubsts<'tcx> { }; tupled_upvars_ty.expect_ty().tuple_fields() } + + #[inline] + pub fn tupled_upvars_ty(self) -> Ty<'tcx> { + match self { + UpvarSubsts::Closure(substs) => substs.as_closure().tupled_upvars_ty(), + UpvarSubsts::Generator(substs) => substs.as_generator().tupled_upvars_ty(), + } + } } #[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index 1bd3bcb6a4d..7d96adb7c8b 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -1,6 +1,5 @@ // Type substitutions. -use crate::infer::canonical::Canonical; use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::sty::{ClosureSubsts, GeneratorSubsts}; @@ -648,8 +647,6 @@ impl<'a, 'tcx> SubstFolder<'a, 'tcx> { } } -pub type CanonicalUserSubsts<'tcx> = Canonical<'tcx, UserSubsts<'tcx>>; - /// Stores the user-given substs to reach some fully qualified path /// (e.g., `<T>::Item` or `<T as Trait>::Item`). #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs index 9d5b558234b..86476dffc03 100644 --- a/compiler/rustc_middle/src/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -123,10 +123,26 @@ impl<'tcx> TyCtxt<'tcx> { self_ty: Ty<'tcx>, mut f: F, ) { + let _: Option<()> = self.find_map_relevant_impl(def_id, self_ty, |did| { + f(did); + None + }); + } + + /// Applies function to every impl that could possibly match the self type `self_ty` and returns + /// the first non-none value. + pub fn find_map_relevant_impl<T, F: FnMut(DefId) -> Option<T>>( + self, + def_id: DefId, + self_ty: Ty<'tcx>, + mut f: F, + ) -> Option<T> { let impls = self.trait_impls_of(def_id); for &impl_def_id in impls.blanket_impls.iter() { - f(impl_def_id); + if let result @ Some(_) = f(impl_def_id) { + return result; + } } // simplify_type(.., false) basically replaces type parameters and @@ -157,14 +173,20 @@ impl<'tcx> TyCtxt<'tcx> { if let Some(simp) = fast_reject::simplify_type(self, self_ty, true) { if let Some(impls) = impls.non_blanket_impls.get(&simp) { for &impl_def_id in impls { - f(impl_def_id); + if let result @ Some(_) = f(impl_def_id) { + return result; + } } } } else { for &impl_def_id in impls.non_blanket_impls.values().flatten() { - f(impl_def_id); + if let result @ Some(_) = f(impl_def_id) { + return result; + } } } + + None } /// Returns an iterator containing all impls diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 4127b6535bc..b0f0f0ba57f 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -6,9 +6,9 @@ use crate::mir::interpret::{sign_extend, truncate}; use crate::ty::fold::TypeFolder; use crate::ty::layout::IntegerExt; use crate::ty::query::TyCtxtAt; -use crate::ty::subst::{GenericArgKind, InternalSubsts, Subst, SubstsRef}; +use crate::ty::subst::{GenericArgKind, Subst, SubstsRef}; use crate::ty::TyKind::*; -use crate::ty::{self, DefIdTree, GenericParamDefKind, List, Ty, TyCtxt, TypeFoldable}; +use crate::ty::{self, DefIdTree, List, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::Float as _; use rustc_ast as ast; use rustc_attr::{self as attr, SignedInt, UnsignedInt}; @@ -341,19 +341,19 @@ impl<'tcx> TyCtxt<'tcx> { pub fn calculate_dtor( self, adt_did: DefId, - validate: &mut dyn FnMut(Self, DefId) -> Result<(), ErrorReported>, + validate: impl Fn(Self, DefId) -> Result<(), ErrorReported>, ) -> Option<ty::Destructor> { let drop_trait = self.lang_items().drop_trait()?; self.ensure().coherent_trait(drop_trait); - let mut dtor_did = None; let ty = self.type_of(adt_did); - self.for_each_relevant_impl(drop_trait, ty, |impl_did| { + let dtor_did = self.find_map_relevant_impl(drop_trait, ty, |impl_did| { if let Some(item) = self.associated_items(impl_did).in_definition_order().next() { if validate(self, impl_did).is_ok() { - dtor_did = Some(item.def_id); + return Some(item.def_id); } } + None }); Some(ty::Destructor { did: dtor_did? }) @@ -509,20 +509,6 @@ impl<'tcx> TyCtxt<'tcx> { Some(ty::Binder::bind(env_ty)) } - /// Given the `DefId` of some item that has no type or const parameters, make - /// a suitable "empty substs" for it. - pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> { - InternalSubsts::for_item(self, item_def_id, |param, _| match param.kind { - GenericParamDefKind::Lifetime => self.lifetimes.re_erased.into(), - GenericParamDefKind::Type { .. } => { - bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) - } - GenericParamDefKind::Const { .. } => { - bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id) - } - }) - } - /// Returns `true` if the node pointed to by `def_id` is a `static` item. pub fn is_static(self, def_id: DefId) -> bool { self.static_mutability(def_id).is_some() @@ -646,8 +632,8 @@ impl<'tcx> ty::TyS<'tcx> { } ty::Char => Some(std::char::MAX as u128), ty::Float(fty) => Some(match fty { - ast::FloatTy::F32 => ::rustc_apfloat::ieee::Single::INFINITY.to_bits(), - ast::FloatTy::F64 => ::rustc_apfloat::ieee::Double::INFINITY.to_bits(), + ast::FloatTy::F32 => rustc_apfloat::ieee::Single::INFINITY.to_bits(), + ast::FloatTy::F64 => rustc_apfloat::ieee::Double::INFINITY.to_bits(), }), _ => None, }; diff --git a/compiler/rustc_mir/src/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs index c84ccafaff5..8c05e6fd5d0 100644 --- a/compiler/rustc_mir/src/borrow_check/invalidation.rs +++ b/compiler/rustc_mir/src/borrow_check/invalidation.rs @@ -117,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> { self.check_activations(location); match &terminator.kind { - TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => { + TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => { self.consume_operand(location, discr); } TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => { diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 9b34db1de40..4b7af271bae 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -671,7 +671,7 @@ impl<'cx, 'tcx> dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tc self.check_activations(loc, span, flow_state); match term.kind { - TerminatorKind::SwitchInt { ref discr, switch_ty: _, values: _, targets: _ } => { + TerminatorKind::SwitchInt { ref discr, switch_ty: _, targets: _ } => { self.consume_operand(loc, (discr, span), flow_state); } TerminatorKind::Drop { place: ref drop_place, target: _, unwind: _ } => { diff --git a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs index f8a8801595a..4fc1c570e46 100644 --- a/compiler/rustc_mir/src/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -1777,7 +1777,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.assert_iscleanup(body, block_data, target, is_cleanup) } TerminatorKind::SwitchInt { ref targets, .. } => { - for target in targets { + for target in targets.all_targets() { self.assert_iscleanup(body, block_data, *target, is_cleanup); } } diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index 57aa216850a..6ef73b04238 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -343,7 +343,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>( // deny-by-default lint _ => { if let Some(p) = cid.promoted { - let span = tcx.promoted_mir_of_opt_const_arg(def.to_global())[p].span; + let span = tcx.promoted_mir_opt_const_arg(def.to_global())[p].span; if let err_inval!(ReferencedConstant) = err.error { Err(err.report_as_error( tcx.at(span), diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 978d2fe0004..4b235e1aa4a 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -50,7 +50,7 @@ pub(crate) fn destructure_const<'tcx>( let (field_count, variant, down) = match val.ty.kind() { ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op), ty::Adt(def, _) if def.variants.is_empty() => { - return mir::DestructuredConst { variant: None, fields: tcx.arena.alloc_slice(&[]) }; + return mir::DestructuredConst { variant: None, fields: &[] }; } ty::Adt(def, _) => { let variant = ecx.read_discriminant(op).unwrap().1; diff --git a/compiler/rustc_mir/src/dataflow/framework/direction.rs b/compiler/rustc_mir/src/dataflow/framework/direction.rs index ca2bb6e0bf7..8a9ced91eb3 100644 --- a/compiler/rustc_mir/src/dataflow/framework/direction.rs +++ b/compiler/rustc_mir/src/dataflow/framework/direction.rs @@ -1,5 +1,5 @@ use rustc_index::bit_set::BitSet; -use rustc_middle::mir::{self, BasicBlock, Location}; +use rustc_middle::mir::{self, BasicBlock, Location, SwitchTargets}; use rustc_middle::ty::TyCtxt; use std::ops::RangeInclusive; @@ -488,11 +488,10 @@ impl Direction for Forward { } } - SwitchInt { ref targets, ref values, ref discr, switch_ty: _ } => { + SwitchInt { ref targets, ref discr, switch_ty: _ } => { let mut applier = SwitchIntEdgeEffectApplier { exit_state, - targets: targets.as_ref(), - values: values.as_ref(), + targets, propagate, effects_applied: false, }; @@ -504,8 +503,8 @@ impl Direction for Forward { } = applier; if !effects_applied { - for &target in targets.iter() { - propagate(target, exit_state); + for target in targets.all_targets() { + propagate(*target, exit_state); } } } @@ -515,8 +514,7 @@ impl Direction for Forward { struct SwitchIntEdgeEffectApplier<'a, D, F> { exit_state: &'a mut D, - values: &'a [u128], - targets: &'a [BasicBlock], + targets: &'a SwitchTargets, propagate: F, effects_applied: bool, @@ -531,7 +529,7 @@ where assert!(!self.effects_applied); let mut tmp = None; - for (&value, &target) in self.values.iter().zip(self.targets.iter()) { + for (value, target) in self.targets.iter() { let tmp = opt_clone_from_or_clone(&mut tmp, self.exit_state); apply_edge_effect(tmp, SwitchIntTarget { value: Some(value), target }); (self.propagate)(target, tmp); @@ -539,7 +537,7 @@ where // Once we get to the final, "otherwise" branch, there is no need to preserve `exit_state`, // so pass it directly to `apply_edge_effect` to save a clone of the dataflow state. - let otherwise = self.targets.last().copied().unwrap(); + let otherwise = self.targets.otherwise(); apply_edge_effect(self.exit_state, SwitchIntTarget { value: None, target: otherwise }); (self.propagate)(otherwise, self.exit_state); diff --git a/compiler/rustc_mir/src/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs index c1e500d01b1..1b7264f86a2 100644 --- a/compiler/rustc_mir/src/dataflow/framework/engine.rs +++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs @@ -62,15 +62,6 @@ where let blocks = mir::traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) } - - pub fn visit_in_rpo_with( - &self, - body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, - ) { - let blocks = mir::traversal::reverse_postorder(body); - visit_results(body, blocks.map(|(bb, _)| bb), self, vis) - } } /// A solver for dataflow problems. diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index 93da6e3d38a..ec1195d3703 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -477,16 +477,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); if let Some(promoted) = promoted { - return Ok(&self.tcx.promoted_mir_of_opt_const_arg(def)[promoted]); + return Ok(&self.tcx.promoted_mir_opt_const_arg(def)[promoted]); } match instance { ty::InstanceDef::Item(def) => { if self.tcx.is_mir_available(def.did) { - if let Some((did, param_did)) = def.as_const_arg() { - Ok(self.tcx.optimized_mir_of_const_arg((did, param_did))) - } else { - Ok(self.tcx.optimized_mir(def.did)) - } + Ok(self.tcx.optimized_mir_opt_const_arg(def)) } else { throw_unsup!(NoMirFor(def.did)) } diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 3718da1723b..66dbacb2f9d 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -3,6 +3,7 @@ //! interpreting common C functions leak into CTFE. use std::borrow::{Borrow, Cow}; +use std::fmt::Debug; use std::hash::Hash; use rustc_middle::mir; @@ -79,19 +80,19 @@ pub trait AllocMap<K: Hash + Eq, V> { /// and some use case dependent behaviour can instead be applied. pub trait Machine<'mir, 'tcx>: Sized { /// Additional memory kinds a machine wishes to distinguish from the builtin ones - type MemoryKind: ::std::fmt::Debug + ::std::fmt::Display + MayLeak + Eq + 'static; + type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static; /// Tag tracked alongside every pointer. This is used to implement "Stacked Borrows" /// <https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html>. /// The `default()` is used for pointers to consts, statics, vtables and functions. /// The `Debug` formatting is used for displaying pointers; we cannot use `Display` /// as `()` does not implement that, but it should be "nice" output. - type PointerTag: ::std::fmt::Debug + Copy + Eq + Hash + 'static; + type PointerTag: Debug + Copy + Eq + Hash + 'static; /// Machines can define extra (non-instance) things that represent values of function pointers. /// For example, Miri uses this to return a function pointer from `dlsym` /// that can later be called to execute the right thing. - type ExtraFnVal: ::std::fmt::Debug + Copy; + type ExtraFnVal: Debug + Copy; /// Extra data stored in every call frame. type FrameExtra; diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index 735f890a33b..d8f27ec9545 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -133,7 +133,7 @@ impl<Tag: Copy> std::fmt::Display for ImmTy<'tcx, Tag> { } } -impl<'tcx, Tag> ::std::ops::Deref for ImmTy<'tcx, Tag> { +impl<'tcx, Tag> std::ops::Deref for ImmTy<'tcx, Tag> { type Target = Immediate<Tag>; #[inline(always)] fn deref(&self) -> &Immediate<Tag> { @@ -156,7 +156,7 @@ pub struct OpTy<'tcx, Tag = ()> { pub layout: TyAndLayout<'tcx>, } -impl<'tcx, Tag> ::std::ops::Deref for OpTy<'tcx, Tag> { +impl<'tcx, Tag> std::ops::Deref for OpTy<'tcx, Tag> { type Target = Operand<Tag>; #[inline(always)] fn deref(&self) -> &Operand<Tag> { @@ -340,7 +340,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { pub fn read_str(&self, mplace: MPlaceTy<'tcx, M::PointerTag>) -> InterpResult<'tcx, &str> { let len = mplace.len(self)?; let bytes = self.memory.read_bytes(mplace.ptr, Size::from_bytes(len))?; - let str = ::std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; + let str = std::str::from_utf8(bytes).map_err(|err| err_ub!(InvalidStr(err)))?; Ok(str) } diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index 72551b23370..fe25f8ce962 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -3,6 +3,7 @@ //! All high-level functions to write to memory work on places as destinations. use std::convert::TryFrom; +use std::fmt::Debug; use std::hash::Hash; use rustc_macros::HashStable; @@ -86,7 +87,7 @@ pub struct PlaceTy<'tcx, Tag = ()> { pub layout: TyAndLayout<'tcx>, } -impl<'tcx, Tag> ::std::ops::Deref for PlaceTy<'tcx, Tag> { +impl<'tcx, Tag> std::ops::Deref for PlaceTy<'tcx, Tag> { type Target = Place<Tag>; #[inline(always)] fn deref(&self) -> &Place<Tag> { @@ -101,7 +102,7 @@ pub struct MPlaceTy<'tcx, Tag = ()> { pub layout: TyAndLayout<'tcx>, } -impl<'tcx, Tag> ::std::ops::Deref for MPlaceTy<'tcx, Tag> { +impl<'tcx, Tag> std::ops::Deref for MPlaceTy<'tcx, Tag> { type Target = MemPlace<Tag>; #[inline(always)] fn deref(&self) -> &MemPlace<Tag> { @@ -226,7 +227,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { } // These are defined here because they produce a place. -impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { +impl<'tcx, Tag: Debug + Copy> OpTy<'tcx, Tag> { #[inline(always)] /// Note: do not call `as_ref` on the resulting place. This function should only be used to /// read from the resulting mplace, not to get its address back. @@ -251,7 +252,7 @@ impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> { } } -impl<Tag: ::std::fmt::Debug> Place<Tag> { +impl<Tag: Debug> Place<Tag> { #[inline] pub fn assert_mem_place(self) -> MemPlace<Tag> { match self { @@ -261,7 +262,7 @@ impl<Tag: ::std::fmt::Debug> Place<Tag> { } } -impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> { +impl<'tcx, Tag: Debug> PlaceTy<'tcx, Tag> { #[inline] pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> { MPlaceTy { mplace: self.place.assert_mem_place(), layout: self.layout } @@ -272,7 +273,7 @@ impl<'tcx, Tag: ::std::fmt::Debug> PlaceTy<'tcx, Tag> { impl<'mir, 'tcx: 'mir, Tag, M> InterpCx<'mir, 'tcx, M> where // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 - Tag: ::std::fmt::Debug + Copy + Eq + Hash + 'static, + Tag: Debug + Copy + Eq + Hash + 'static, M: Machine<'mir, 'tcx, PointerTag = Tag>, // FIXME: Working around https://github.com/rust-lang/rust/issues/24159 M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKind>, Allocation<Tag, M::AllocExtra>)>, diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index 9f200ca62b8..bb11c2a23bd 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -24,16 +24,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Goto { target } => self.go_to_block(target), - SwitchInt { ref discr, ref values, ref targets, switch_ty } => { + SwitchInt { ref discr, ref targets, switch_ty } => { let discr = self.read_immediate(self.eval_operand(discr, None)?)?; trace!("SwitchInt({:?})", *discr); assert_eq!(discr.layout.ty, switch_ty); // Branch to the `otherwise` case by default, if no match is found. - assert!(!targets.is_empty()); - let mut target_block = targets[targets.len() - 1]; + assert!(!targets.iter().is_empty()); + let mut target_block = targets.otherwise(); - for (index, &const_int) in values.iter().enumerate() { + for (const_int, target) in targets.iter() { // Compare using binary_op, to also support pointer values let res = self .overflowing_binary_op( @@ -43,7 +43,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { )? .0; if res.to_bool()? { - target_block = targets[index]; + target_block = target; break; } } diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index 7e12cc9176e..417176564b9 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -197,6 +197,7 @@ use rustc_session::config::EntryFnType; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; use smallvec::SmallVec; use std::iter; +use std::ops::Range; use std::path::PathBuf; #[derive(PartialEq)] @@ -210,9 +211,8 @@ pub enum MonoItemCollectionMode { pub struct InliningMap<'tcx> { // Maps a source mono item to the range of mono items // accessed by it. - // The two numbers in the tuple are the start (inclusive) and - // end index (exclusive) within the `targets` vecs. - index: FxHashMap<MonoItem<'tcx>, (usize, usize)>, + // The range selects elements within the `targets` vecs. + index: FxHashMap<MonoItem<'tcx>, Range<usize>>, targets: Vec<MonoItem<'tcx>>, // Contains one bit per mono item in the `targets` field. That bit @@ -245,7 +245,7 @@ impl<'tcx> InliningMap<'tcx> { } let end_index = self.targets.len(); - assert!(self.index.insert(source, (start_index, end_index)).is_none()); + assert!(self.index.insert(source, start_index..end_index).is_none()); } // Internally iterate over all items referenced by `source` which will be @@ -254,9 +254,9 @@ impl<'tcx> InliningMap<'tcx> { where F: FnMut(MonoItem<'tcx>), { - if let Some(&(start_index, end_index)) = self.index.get(&source) { - for (i, candidate) in self.targets[start_index..end_index].iter().enumerate() { - if self.inlines.contains(start_index + i) { + if let Some(range) = self.index.get(&source) { + for (i, candidate) in self.targets[range.clone()].iter().enumerate() { + if self.inlines.contains(range.start + i) { f(*candidate); } } @@ -268,8 +268,8 @@ impl<'tcx> InliningMap<'tcx> { where F: FnMut(MonoItem<'tcx>, &[MonoItem<'tcx>]), { - for (&accessor, &(start_index, end_index)) in &self.index { - f(accessor, &self.targets[start_index..end_index]) + for (&accessor, range) in &self.index { + f(accessor, &self.targets[range.clone()]) } } } diff --git a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs index 3c89111a659..5083a45b539 100644 --- a/compiler/rustc_mir/src/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -532,7 +532,7 @@ fn mono_item_visibility( } fn default_visibility(tcx: TyCtxt<'_>, id: DefId, is_generic: bool) -> Visibility { - if !tcx.sess.target.target.options.default_hidden_visibility { + if !tcx.sess.target.options.default_hidden_visibility { return Visibility::Default; } diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs index 4d4e9b98917..fb89b36060a 100644 --- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -34,7 +34,6 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> { let def_id = self.is_const_item(local)?; - let mut any_dtor = |_tcx, _def_id| Ok(()); // We avoid linting mutation of a const item if the const's type has a // Drop impl. The Drop logic observes the mutation which was performed. @@ -54,7 +53,7 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> { // // #[const_mutation_allowed] // pub const LOG: Log = Log { msg: "" }; - match self.tcx.calculate_dtor(def_id, &mut any_dtor) { + match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) { Some(_) => None, None => Some(def_id), } diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 237a5c7864b..f97dcf4852d 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -1,7 +1,7 @@ use crate::{transform::MirPass, util::patch::MirPatch}; use rustc_middle::mir::*; use rustc_middle::ty::{Ty, TyCtxt}; -use std::{borrow::Cow, fmt::Debug}; +use std::fmt::Debug; use super::simplify::simplify_cfg; @@ -95,15 +95,17 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)), ); - let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply + let new_targets = opt_to_apply .infos .iter() .flat_map(|x| x.second_switch_info.targets_with_values.iter()) - .cloned() - .unzip(); + .cloned(); + + let targets = SwitchTargets::new( + new_targets, + opt_to_apply.infos[0].first_switch_info.otherwise_bb, + ); - // add otherwise case in the end - targets_to_jump_to.push(opt_to_apply.infos[0].first_switch_info.otherwise_bb); // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal let new_switch_data = BasicBlockData::new(Some(Terminator { source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info, @@ -111,8 +113,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // the first and second discriminants are equal, so just pick one discr: Operand::Copy(first_descriminant_place), switch_ty: discr_type, - values: Cow::from(values_to_jump_to), - targets: targets_to_jump_to, + targets, }, })); @@ -176,7 +177,7 @@ struct SwitchDiscriminantInfo<'tcx> { /// The basic block that the otherwise branch points to otherwise_bb: BasicBlock, /// Target along with the value being branched from. Otherwise is not included - targets_with_values: Vec<(BasicBlock, u128)>, + targets_with_values: Vec<(u128, BasicBlock)>, discr_source_info: SourceInfo, /// The place of the discriminant used in the switch discr_used_in_switch: Place<'tcx>, @@ -211,7 +212,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { let discr = self.find_switch_discriminant_info(bb, switch)?; // go through each target, finding a discriminant read, and a switch - let results = discr.targets_with_values.iter().map(|(target, value)| { + let results = discr.targets_with_values.iter().map(|(value, target)| { self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone()) }); @@ -253,7 +254,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { } // check that the value being matched on is the same. The - if this_bb_discr_info.targets_with_values.iter().find(|x| x.1 == value).is_none() { + if this_bb_discr_info.targets_with_values.iter().find(|x| x.0 == value).is_none() { trace!("NO: values being matched on are not the same"); return None; } @@ -270,7 +271,7 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { // ``` // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch if !(this_bb_discr_info.targets_with_values.len() == 1 - && this_bb_discr_info.targets_with_values[0].1 == value) + && this_bb_discr_info.targets_with_values[0].0 == value) { trace!( "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here" @@ -296,18 +297,14 @@ impl<'a, 'tcx> Helper<'a, 'tcx> { switch: &Terminator<'tcx>, ) -> Option<SwitchDiscriminantInfo<'tcx>> { match &switch.kind { - TerminatorKind::SwitchInt { discr, targets, values, .. } => { + TerminatorKind::SwitchInt { discr, targets, .. } => { let discr_local = discr.place()?.as_local()?; // the declaration of the discriminant read. Place of this read is being used in the switch let discr_decl = &self.body.local_decls()[discr_local]; let discr_ty = discr_decl.ty; // the otherwise target lies as the last element - let otherwise_bb = targets.get(values.len())?.clone(); - let targets_with_values = targets - .iter() - .zip(values.iter()) - .map(|(t, v)| (t.clone(), v.clone())) - .collect(); + let otherwise_bb = targets.otherwise(); + let targets_with_values = targets.iter().collect(); // find the place of the adt where the discriminant is being read from // assume this is the last statement of the block diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index 924bb4996fc..039d4753a8c 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -71,7 +71,6 @@ use rustc_middle::ty::GeneratorSubsts; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use rustc_target::spec::PanicStrategy; -use std::borrow::Cow; use std::{iter, ops}; pub struct StateTransform; @@ -839,11 +838,12 @@ fn insert_switch<'tcx>( ) { let default_block = insert_term_block(body, default); let (assign, discr) = transform.get_discr(body); + let switch_targets = + SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block); let switch = TerminatorKind::SwitchInt { discr: Operand::Move(discr), switch_ty: transform.discr_ty, - values: Cow::from(cases.iter().map(|&(i, _)| i as u128).collect::<Vec<_>>()), - targets: cases.iter().map(|&(_, d)| d).chain(iter::once(default_block)).collect(), + targets: switch_targets, }; let source_info = SourceInfo::outermost(body.span); diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index bec1eb79047..34aaefdcbea 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -771,7 +771,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> { *target = self.update_target(*target); } TerminatorKind::SwitchInt { ref mut targets, .. } => { - for tgt in targets { + for tgt in targets.all_targets_mut() { *tgt = self.update_target(*tgt); } } diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs index babe10a0f14..6824c73ab60 100644 --- a/compiler/rustc_mir/src/transform/instrument_coverage.rs +++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs @@ -22,9 +22,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::DefId; use rustc_span::source_map::original_sp; -use rustc_span::{ - BytePos, CharPos, FileName, Pos, RealFileName, SourceFile, Span, Symbol, SyntaxContext, -}; +use rustc_span::{BytePos, CharPos, Pos, SourceFile, Span, Symbol, SyntaxContext}; use std::cmp::Ordering; @@ -549,13 +547,7 @@ impl<'a, 'tcx> Instrumentor<'a, 'tcx> { let mir_body = &self.mir_body; let body_span = self.body_span(); let source_file = source_map.lookup_source_file(body_span.lo()); - let file_name = match &source_file.name { - FileName::Real(RealFileName::Named(path)) => Symbol::intern(&path.to_string_lossy()), - _ => bug!( - "source_file.name should be a RealFileName, but it was: {:?}", - source_file.name - ), - }; + let file_name = Symbol::intern(&source_file.name.to_string()); debug!("instrumenting {:?}, span: {}", def_id, source_map.span_to_string(body_span)); diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index dad3812c5cd..8b2d6b09aa8 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -46,10 +46,13 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { discr: Operand::Copy(ref place) | Operand::Move(ref place), switch_ty, ref targets, - ref values, .. - } if targets.len() == 2 && values.len() == 1 && targets[0] != targets[1] => { - (place, values[0], switch_ty, targets[0], targets[1]) + } if targets.iter().len() == 1 => { + let (value, target) = targets.iter().next().unwrap(); + if target == targets.otherwise() { + continue; + } + (place, value, switch_ty, target, targets.otherwise()) } // Only optimize switch int statements _ => continue, diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index b4f5947f5a3..ffb84950fc9 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -137,7 +137,7 @@ fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> FxHashSet<LocalDefId> { /// Generates a default name for the pass based on the name of the /// type `T`. pub fn default_name<T: ?Sized>() -> Cow<'static, str> { - let name = ::std::any::type_name::<T>(); + let name = std::any::type_name::<T>(); if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) } } @@ -287,11 +287,7 @@ fn mir_promoted( // this point, before we steal the mir-const result. // Also this means promotion can rely on all const checks having been done. let _ = tcx.mir_const_qualif_opt_const_arg(def); - let _ = if let Some(param_did) = def.const_param_did { - tcx.mir_abstract_const_of_const_arg((def.did, param_did)) - } else { - tcx.mir_abstract_const(def.did.to_def_id()) - }; + let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global()); let mut body = tcx.mir_const(def).steal(); let mut required_consts = Vec::new(); diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index 7abc998d388..7373abcc820 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -124,6 +124,15 @@ impl Candidate { Candidate::Argument { .. } | Candidate::InlineAsm { .. } => true, } } + + fn source_info(&self, body: &Body<'_>) -> SourceInfo { + match self { + Candidate::Ref(location) | Candidate::Repeat(location) => *body.source_info(*location), + Candidate::Argument { bb, .. } | Candidate::InlineAsm { bb, .. } => { + *body.source_info(body.terminator_loc(*bb)) + } + } + } } fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> { @@ -953,6 +962,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { from_hir_call, fn_span, }, + source_info: SourceInfo::outermost(terminator.source_info.span), ..terminator }; } @@ -1163,12 +1173,13 @@ pub fn promote_candidates<'tcx>( // Declare return place local so that `mir::Body::new` doesn't complain. let initial_locals = iter::once(LocalDecl::new(tcx.types.never, body.span)).collect(); + let mut scope = body.source_scopes[candidate.source_info(body).scope].clone(); + scope.parent_scope = None; + let mut promoted = Body::new( body.source, // `promoted` gets filled in below IndexVec::new(), - // FIXME: maybe try to filter this to avoid blowing up - // memory usage? - body.source_scopes.clone(), + IndexVec::from_elem_n(scope, 1), initial_locals, IndexVec::new(), 0, diff --git a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs index b45c533d2c0..31e201c3a5b 100644 --- a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs @@ -43,7 +43,7 @@ impl RemoveNoopLandingPads { // These are all nops in a landing pad } - StatementKind::Assign(box (place, Rvalue::Use(_))) => { + StatementKind::Assign(box (place, Rvalue::Use(_) | Rvalue::Discriminant(_))) => { if place.as_local().is_some() { // Writing to a local (e.g., a drop flag) does not // turn a landing pad to a non-nop diff --git a/compiler/rustc_mir/src/transform/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs index 161856a38ee..5f63c03993d 100644 --- a/compiler/rustc_mir/src/transform/simplify_branches.rs +++ b/compiler/rustc_mir/src/transform/simplify_branches.rs @@ -29,17 +29,16 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranches { TerminatorKind::SwitchInt { discr: Operand::Constant(ref c), switch_ty, - ref values, ref targets, .. } => { let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty); if let Some(constant) = constant { - let (otherwise, targets) = targets.split_last().unwrap(); - let mut ret = TerminatorKind::Goto { target: *otherwise }; - for (&v, t) in values.iter().zip(targets.iter()) { + let otherwise = targets.otherwise(); + let mut ret = TerminatorKind::Goto { target: otherwise }; + for (v, t) in targets.iter() { if v == constant { - ret = TerminatorKind::Goto { target: *t }; + ret = TerminatorKind::Goto { target: t }; break; } } diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs index 9f837cf78a6..6372f8960dd 100644 --- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -1,8 +1,10 @@ +use std::iter; + use super::MirPass; use rustc_middle::{ mir::{ interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement, - StatementKind, TerminatorKind, + StatementKind, SwitchTargets, TerminatorKind, }, ty::{Ty, TyCtxt}, }; @@ -43,19 +45,21 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { Scalar::Ptr(_) => continue, }; const FALSE: u128 = 0; - let mut new_targets = opt.targets.clone(); - let first_is_false_target = opt.values[0] == FALSE; + + let mut new_targets = opt.targets; + let first_value = new_targets.iter().next().unwrap().0; + let first_is_false_target = first_value == FALSE; match opt.op { BinOp::Eq => { // if the assignment was Eq we want the true case to be first if first_is_false_target { - new_targets.swap(0, 1); + new_targets.all_targets_mut().swap(0, 1); } } BinOp::Ne => { // if the assignment was Ne we want the false case to be first if !first_is_false_target { - new_targets.swap(0, 1); + new_targets.all_targets_mut().swap(0, 1); } } _ => unreachable!(), @@ -96,7 +100,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { } storage_deads_to_remove.push((stmt_idx, opt.bb_idx)); // if we have StorageDeads to remove then make sure to insert them at the top of each target - for bb_idx in new_targets.iter() { + for bb_idx in new_targets.all_targets() { storage_deads_to_insert.push(( *bb_idx, Statement { @@ -107,13 +111,18 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { } } - let terminator = bb.terminator_mut(); + let [bb_cond, bb_otherwise] = match new_targets.all_targets() { + [a, b] => [*a, *b], + e => bug!("expected 2 switch targets, got: {:?}", e), + }; + + let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise); + let terminator = bb.terminator_mut(); terminator.kind = TerminatorKind::SwitchInt { discr: Operand::Move(opt.to_switch_on), switch_ty: opt.branch_value_ty, - values: vec![new_value].into(), - targets: new_targets, + targets, }; } @@ -138,15 +147,13 @@ impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> { .iter_enumerated() .filter_map(|(bb_idx, bb)| { // find switch - let (place_switched_on, values, targets, place_switched_on_moved) = match &bb - .terminator() - .kind - { - rustc_middle::mir::TerminatorKind::SwitchInt { - discr, values, targets, .. - } => Some((discr.place()?, values, targets, discr.is_move())), - _ => None, - }?; + let (place_switched_on, targets, place_switched_on_moved) = + match &bb.terminator().kind { + rustc_middle::mir::TerminatorKind::SwitchInt { discr, targets, .. } => { + Some((discr.place()?, targets, discr.is_move())) + } + _ => None, + }?; // find the statement that assigns the place being switched on bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| { @@ -167,7 +174,6 @@ impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> { branch_value_scalar, branch_value_ty, op: *op, - values: values.clone().into_owned(), targets: targets.clone(), }) } @@ -220,8 +226,6 @@ struct OptimizationInfo<'tcx> { branch_value_ty: Ty<'tcx>, /// Either Eq or Ne op: BinOp, - /// Current values used in the switch target. This needs to be replaced with the branch_value - values: Vec<u128>, /// Current targets used in the switch - targets: Vec<BasicBlock>, + targets: SwitchTargets, } diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index a4e7a5a9453..27bb1def726 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -576,15 +576,13 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { .iter_enumerated() .filter_map(|(bb_idx, bb)| { let (discr_switched_on, targets_and_values) = match &bb.terminator().kind { - TerminatorKind::SwitchInt { targets, discr, values, .. } => { - // if values.len() == targets.len() - 1, we need to include None where no value is present - // such that the zip does not throw away targets. If no `otherwise` case is in targets, the zip will simply throw away the added None - let values_extended = values.iter().map(|x|Some(*x)).chain(once(None)); - let targets_and_values:Vec<_> = targets.iter().zip(values_extended) - .map(|(target, value)| SwitchTargetAndValue{target:*target, value}) + TerminatorKind::SwitchInt { targets, discr, .. } => { + let targets_and_values: Vec<_> = targets.iter() + .map(|(val, target)| SwitchTargetAndValue { target, value: Some(val) }) + .chain(once(SwitchTargetAndValue { target: targets.otherwise(), value: None })) .collect(); - assert_eq!(targets.len(), targets_and_values.len()); - (discr, targets_and_values)}, + (discr, targets_and_values) + }, _ => return None, }; diff --git a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs index 87906e83ed5..465832c89fd 100644 --- a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs +++ b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs @@ -3,7 +3,8 @@ use crate::transform::MirPass; use rustc_data_structures::stable_set::FxHashSet; use rustc_middle::mir::{ - BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind, + BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets, + TerminatorKind, }; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; @@ -101,21 +102,15 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching { trace!("allowed_variants = {:?}", allowed_variants); - if let TerminatorKind::SwitchInt { values, targets, .. } = + if let TerminatorKind::SwitchInt { targets, .. } = &mut body.basic_blocks_mut()[bb].terminator_mut().kind { - // take otherwise out early - let otherwise = targets.pop().unwrap(); - assert_eq!(targets.len(), values.len()); - let mut i = 0; - targets.retain(|_| { - let keep = allowed_variants.contains(&values[i]); - i += 1; - keep - }); - targets.push(otherwise); - - values.to_mut().retain(|var| allowed_variants.contains(var)); + let new_targets = SwitchTargets::new( + targets.iter().filter(|(val, _)| allowed_variants.contains(val)), + targets.otherwise(), + ); + + *targets = new_targets; } else { unreachable!() } diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs index c6426a06ea1..f6d39dae342 100644 --- a/compiler/rustc_mir/src/transform/unreachable_prop.rs +++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs @@ -7,7 +7,6 @@ use crate::transform::MirPass; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; -use std::borrow::Cow; pub struct UnreachablePropagation; @@ -69,14 +68,15 @@ where { let terminator = match *terminator_kind { TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable, - TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { - let original_targets_len = targets.len(); - let (otherwise, targets) = targets.split_last().unwrap(); + TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => { + let otherwise = targets.otherwise(); + + let original_targets_len = targets.iter().len() + 1; let (mut values, mut targets): (Vec<_>, Vec<_>) = - values.iter().zip(targets.iter()).filter(|(_, &t)| !predicate(t)).unzip(); + targets.iter().filter(|(_, bb)| !predicate(*bb)).unzip(); - if !predicate(*otherwise) { - targets.push(*otherwise); + if !predicate(otherwise) { + targets.push(otherwise); } else { values.pop(); } @@ -91,8 +91,10 @@ where TerminatorKind::SwitchInt { discr: discr.clone(), switch_ty, - values: Cow::from(values), - targets, + targets: SwitchTargets::new( + values.iter().copied().zip(targets.iter().copied()), + *targets.last().unwrap(), + ), } } else { return None; diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index cf51e86c5bc..beffffa727e 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -8,7 +8,7 @@ use super::MirPass; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue, - Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, + SourceScope, Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, }; use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt}; @@ -229,9 +229,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } - fn visit_var_debug_info(&mut self, _var_debug_info: &VarDebugInfo<'tcx>) { + fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo<'tcx>) { // Debuginfo can contain field projections, which count as a use of the base local. Skip // debuginfo so that we avoid the storage liveness assertion in that case. + self.visit_source_info(&var_debug_info.source_info); } fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { @@ -334,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { TerminatorKind::Goto { target } => { self.check_edge(location, *target, EdgeKind::Normal); } - TerminatorKind::SwitchInt { targets, values, switch_ty, discr } => { + TerminatorKind::SwitchInt { targets, switch_ty, discr } => { let ty = discr.ty(&self.body.local_decls, self.tcx); if ty != *switch_ty { self.fail( @@ -345,19 +346,10 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ), ); } - if targets.len() != values.len() + 1 { - self.fail( - location, - format!( - "encountered `SwitchInt` terminator with {} values, but {} targets (should be values+1)", - values.len(), - targets.len(), - ), - ); - } - for target in targets { - self.check_edge(location, *target, EdgeKind::Normal); + for (_, target) in targets.iter() { + self.check_edge(location, target, EdgeKind::Normal); } + self.check_edge(location, targets.otherwise(), EdgeKind::Normal); } TerminatorKind::Drop { target, unwind, .. } => { self.check_edge(location, *target, EdgeKind::Normal); @@ -441,4 +433,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | TerminatorKind::GeneratorDrop => {} } } + + fn visit_source_scope(&mut self, scope: &SourceScope) { + if self.body.source_scopes.get(*scope).is_none() { + self.tcx.sess.diagnostic().delay_span_bug( + self.body.span, + &format!( + "broken MIR in {:?} ({}):\ninvalid source scope {:?}", + self.body.source.instance, self.when, scope, + ), + ); + } + } } diff --git a/compiler/rustc_mir/src/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs index 43fa15d7e49..0e2d8e5495b 100644 --- a/compiler/rustc_mir/src/util/elaborate_drops.rs +++ b/compiler/rustc_mir/src/util/elaborate_drops.rs @@ -588,8 +588,10 @@ where kind: TerminatorKind::SwitchInt { discr: Operand::Move(discr), switch_ty: discr_ty, - values: From::from(values.to_owned()), - targets: blocks, + targets: SwitchTargets::new( + values.iter().copied().zip(blocks.iter().copied()), + *blocks.last().unwrap(), + ), }, }), is_cleanup: unwind.is_cleanup(), @@ -758,8 +760,6 @@ where let elem_size = Place::from(self.new_temp(tcx.types.usize)); let len = Place::from(self.new_temp(tcx.types.usize)); - static USIZE_SWITCH_ZERO: &[u128] = &[0]; - let base_block = BasicBlockData { statements: vec![ self.assign(elem_size, Rvalue::NullaryOp(NullOp::SizeOf, ety)), @@ -771,11 +771,11 @@ where kind: TerminatorKind::SwitchInt { discr: move_(elem_size), switch_ty: tcx.types.usize, - values: From::from(USIZE_SWITCH_ZERO), - targets: vec![ + targets: SwitchTargets::static_if( + 0, self.drop_loop_pair(ety, false, len), self.drop_loop_pair(ety, true, len), - ], + ), }, }), }; diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index a28a181e935..e46274770be 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -28,8 +28,9 @@ use std::mem; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Simplify a candidate so that all match pairs require a test. /// - /// This method will also split a candidate where the only match-pair is an - /// or-pattern into multiple candidates. This is so that + /// This method will also split a candidate, in which the only + /// match-pair is an or-pattern, into multiple candidates. + /// This is so that /// /// match x { /// 0 | 1 => { ... }, diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 02dcf0394f6..c4191900147 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -167,48 +167,42 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_blocks = make_target_blocks(self); // Variants is a BitVec of indexes into adt_def.variants. let num_enum_variants = adt_def.variants.len(); - let used_variants = variants.count(); debug_assert_eq!(target_blocks.len(), num_enum_variants + 1); let otherwise_block = *target_blocks.last().unwrap(); - let mut targets = Vec::with_capacity(used_variants + 1); - let mut values = Vec::with_capacity(used_variants); let tcx = self.hir.tcx(); - for (idx, discr) in adt_def.discriminants(tcx) { - if variants.contains(idx) { - debug_assert_ne!( - target_blocks[idx.index()], - otherwise_block, - "no canididates for tested discriminant: {:?}", - discr, - ); - values.push(discr.val); - targets.push(target_blocks[idx.index()]); - } else { - debug_assert_eq!( - target_blocks[idx.index()], - otherwise_block, - "found canididates for untested discriminant: {:?}", - discr, - ); - } - } - targets.push(otherwise_block); - debug!( - "num_enum_variants: {}, tested variants: {:?}, variants: {:?}", - num_enum_variants, values, variants + let switch_targets = SwitchTargets::new( + adt_def.discriminants(tcx).filter_map(|(idx, discr)| { + if variants.contains(idx) { + debug_assert_ne!( + target_blocks[idx.index()], + otherwise_block, + "no canididates for tested discriminant: {:?}", + discr, + ); + Some((discr.val, target_blocks[idx.index()])) + } else { + debug_assert_eq!( + target_blocks[idx.index()], + otherwise_block, + "found canididates for untested discriminant: {:?}", + discr, + ); + None + } + }), + otherwise_block, ); + debug!("num_enum_variants: {}, variants: {:?}", num_enum_variants, variants); let discr_ty = adt_def.repr.discr_type().to_ty(tcx); let discr = self.temp(discr_ty, test.span); self.cfg.push_assign(block, source_info, discr, Rvalue::Discriminant(place)); - assert_eq!(values.len() + 1, targets.len()); self.cfg.terminate( block, source_info, TerminatorKind::SwitchInt { discr: Operand::Move(discr), switch_ty: discr_ty, - values: From::from(values), - targets, + targets: switch_targets, }, ); } @@ -230,11 +224,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { // The switch may be inexhaustive so we have a catch all block debug_assert_eq!(options.len() + 1, target_blocks.len()); + let otherwise_block = *target_blocks.last().unwrap(); + let switch_targets = SwitchTargets::new( + options.values().copied().zip(target_blocks), + otherwise_block, + ); TerminatorKind::SwitchInt { discr: Operand::Copy(place), switch_ty, - values: options.values().copied().collect(), - targets: target_blocks, + targets: switch_targets, } }; self.cfg.terminate(block, source_info, terminator); 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 047bf7db4c8..69de7c7e2ee 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -71,13 +71,13 @@ impl<'tcx> Visitor<'tcx> for MatchVisitor<'_, 'tcx> { hir::LocalSource::AwaitDesugar => ("`await` future binding", None), }; self.check_irrefutable(&loc.pat, msg, sp); - self.check_patterns(false, &loc.pat); + self.check_patterns(&loc.pat); } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { intravisit::walk_param(self, param); self.check_irrefutable(¶m.pat, "function argument", None); - self.check_patterns(false, ¶m.pat); + self.check_patterns(¶m.pat); } } @@ -96,14 +96,14 @@ impl PatCtxt<'_, '_> { } PatternError::FloatBug => { // FIXME(#31407) this is only necessary because float parsing is buggy - ::rustc_middle::mir::interpret::struct_error( + rustc_middle::mir::interpret::struct_error( self.tcx.at(pat_span), "could not evaluate float literal (see issue #31407)", ) .emit(); } PatternError::NonConstPath(span) => { - ::rustc_middle::mir::interpret::struct_error( + rustc_middle::mir::interpret::struct_error( self.tcx.at(span), "runtime values cannot be referenced in patterns", ) @@ -119,10 +119,7 @@ impl PatCtxt<'_, '_> { } impl<'tcx> MatchVisitor<'_, 'tcx> { - fn check_patterns(&mut self, has_guard: bool, pat: &Pat<'_>) { - if !self.tcx.features().move_ref_pattern { - check_legality_of_move_bindings(self, has_guard, pat); - } + fn check_patterns(&mut self, pat: &Pat<'_>) { pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); if !self.tcx.features().bindings_after_at { check_legality_of_bindings_in_at_patterns(self, pat); @@ -165,7 +162,7 @@ impl<'tcx> MatchVisitor<'_, 'tcx> { ) { for arm in arms { // Check the arm for some things unrelated to exhaustiveness. - self.check_patterns(arm.guard.is_some(), &arm.pat); + self.check_patterns(&arm.pat); } let mut cx = self.new_cx(scrut.hir_id); @@ -601,65 +598,6 @@ fn is_binding_by_move(cx: &MatchVisitor<'_, '_>, hir_id: HirId, span: Span) -> b !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env) } -/// Check the legality of legality of by-move bindings. -fn check_legality_of_move_bindings(cx: &mut MatchVisitor<'_, '_>, has_guard: bool, pat: &Pat<'_>) { - let sess = cx.tcx.sess; - let typeck_results = cx.typeck_results; - - // Find all by-ref spans. - let mut by_ref_spans = Vec::new(); - pat.each_binding(|_, hir_id, span, _| { - if let Some(ty::BindByReference(_)) = - typeck_results.extract_binding_mode(sess, hir_id, span) - { - by_ref_spans.push(span); - } - }); - - // Find bad by-move spans: - let by_move_spans = &mut Vec::new(); - let mut check_move = |p: &Pat<'_>, sub: Option<&Pat<'_>>| { - // Check legality of moving out of the enum. - // - // `x @ Foo(..)` is legal, but `x @ Foo(y)` isn't. - if sub.map_or(false, |p| p.contains_bindings()) { - struct_span_err!(sess, p.span, E0007, "cannot bind by-move with sub-bindings") - .span_label(p.span, "binds an already bound by-move value by moving it") - .emit(); - } else if !has_guard && !by_ref_spans.is_empty() { - by_move_spans.push(p.span); - } - }; - pat.walk_always(|p| { - if let hir::PatKind::Binding(.., sub) = &p.kind { - if let Some(ty::BindByValue(_)) = - typeck_results.extract_binding_mode(sess, p.hir_id, p.span) - { - if is_binding_by_move(cx, p.hir_id, p.span) { - check_move(p, sub.as_deref()); - } - } - } - }); - - // Found some bad by-move spans, error! - if !by_move_spans.is_empty() { - let mut err = feature_err( - &sess.parse_sess, - sym::move_ref_pattern, - by_move_spans.clone(), - "binding by-move and by-ref in the same pattern is unstable", - ); - for span in by_ref_spans.iter() { - err.span_label(*span, "by-ref pattern here"); - } - for span in by_move_spans.iter() { - err.span_label(*span, "by-move pattern here"); - } - err.emit(); - } -} - /// Check that there are no borrow or move conflicts in `binding @ subpat` patterns. /// /// For example, this would reject: diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 718ed78889f..d46e9a98825 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -1060,13 +1060,13 @@ crate fn compare_const_vals<'tcx>( use rustc_apfloat::Float; return match *ty.kind() { ty::Float(ast::FloatTy::F32) => { - let l = ::rustc_apfloat::ieee::Single::from_bits(a); - let r = ::rustc_apfloat::ieee::Single::from_bits(b); + let l = rustc_apfloat::ieee::Single::from_bits(a); + let r = rustc_apfloat::ieee::Single::from_bits(b); l.partial_cmp(&r) } ty::Float(ast::FloatTy::F64) => { - let l = ::rustc_apfloat::ieee::Double::from_bits(a); - let r = ::rustc_apfloat::ieee::Double::from_bits(b); + let l = rustc_apfloat::ieee::Double::from_bits(a); + let r = rustc_apfloat::ieee::Double::from_bits(b); l.partial_cmp(&r) } ty::Int(ity) => { diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index b68d36c9a8e..25deb46e147 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -7,7 +7,7 @@ #![feature(or_patterns)] use rustc_ast as ast; -use rustc_ast::token::{self, Nonterminal, Token, TokenKind}; +use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; @@ -114,16 +114,6 @@ pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option<Spa source_file_to_parser(sess, file_to_source_file(sess, path, sp)) } -/// Creates a new parser, returning buffered diagnostics if the file doesn't exist, -/// or from lexing the initial token stream. -pub fn maybe_new_parser_from_file<'a>( - sess: &'a ParseSess, - path: &Path, -) -> Result<Parser<'a>, Vec<Diagnostic>> { - let file = try_file_to_source_file(sess, path, None).map_err(|db| vec![db])?; - maybe_source_file_to_parser(sess, file) -} - /// Given a `source_file` and config, returns a parser. fn source_file_to_parser(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Parser<'_> { panictry_buffer!(&sess.span_diagnostic, maybe_source_file_to_parser(sess, source_file)) @@ -146,12 +136,6 @@ fn maybe_source_file_to_parser( Ok(parser) } -// Must preserve old name for now, because `quote!` from the *existing* -// compiler expands into it. -pub fn new_parser_from_tts(sess: &ParseSess, tts: Vec<TokenTree>) -> Parser<'_> { - stream_to_parser(sess, tts.into_iter().collect(), crate::MACRO_ARGUMENTS) -} - // Base abstractions /// Given a session and a path and an optional span (for error reporting), @@ -297,7 +281,11 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke }; // FIXME(#43081): Avoid this pretty-print + reparse hack - let source = pprust::nonterminal_to_string(nt); + // Pretty-print the AST struct without inserting any parenthesis + // beyond those explicitly written by the user (e.g. `ExpnKind::Paren`). + // The resulting stream may have incorrect precedence, but it's only + // ever used for a comparison against the capture tokenstream. + let source = pprust::nonterminal_to_string_no_extra_parens(nt); let filename = FileName::macro_expansion_source_code(&source); let reparsed_tokens = parse_stream_from_source_str(filename, source, sess, Some(span)); @@ -325,15 +313,43 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess) { + // Compare with a non-relaxed delim match to start. + if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess, false) { return tokens; } + + // The check failed. This time, we pretty-print the AST struct with parenthesis + // inserted to preserve precedence. This may cause `None`-delimiters in the captured + // token stream to match up with inserted parenthesis in the reparsed stream. + let source_with_parens = pprust::nonterminal_to_string(nt); + let filename_with_parens = FileName::macro_expansion_source_code(&source_with_parens); + let reparsed_tokens_with_parens = parse_stream_from_source_str( + filename_with_parens, + source_with_parens, + sess, + Some(span), + ); + + // Compare with a relaxed delim match - we want inserted parenthesis in the + // reparsed stream to match `None`-delimiters in the original stream. + if tokenstream_probably_equal_for_proc_macro( + &tokens, + &reparsed_tokens_with_parens, + sess, + true, + ) { + return tokens; + } + info!( "cached tokens found, but they're not \"probably equal\", \ going with stringified version" ); - info!("cached tokens: {:?}", tokens); - info!("reparsed tokens: {:?}", reparsed_tokens); + info!("cached tokens: {}", pprust::tts_to_string(&tokens)); + info!("reparsed tokens: {}", pprust::tts_to_string(&reparsed_tokens_with_parens)); + + info!("cached tokens debug: {:?}", tokens); + info!("reparsed tokens debug: {:?}", reparsed_tokens_with_parens); } reparsed_tokens } @@ -347,6 +363,7 @@ pub fn tokenstream_probably_equal_for_proc_macro( tokens: &TokenStream, reparsed_tokens: &TokenStream, sess: &ParseSess, + relaxed_delim_match: bool, ) -> bool { // When checking for `probably_eq`, we ignore certain tokens that aren't // preserved in the AST. Because they are not preserved, the pretty @@ -472,7 +489,9 @@ pub fn tokenstream_probably_equal_for_proc_macro( let tokens = tokens.trees().flat_map(|t| expand_token(t, sess)); let reparsed_tokens = reparsed_tokens.trees().flat_map(|t| expand_token(t, sess)); - tokens.eq_by(reparsed_tokens, |t, rt| tokentree_probably_equal_for_proc_macro(&t, &rt, sess)) + tokens.eq_by(reparsed_tokens, |t, rt| { + tokentree_probably_equal_for_proc_macro(&t, &rt, sess, relaxed_delim_match) + }) } // See comments in `Nonterminal::to_tokenstream` for why we care about @@ -484,6 +503,7 @@ pub fn tokentree_probably_equal_for_proc_macro( token: &TokenTree, reparsed_token: &TokenTree, sess: &ParseSess, + relaxed_delim_match: bool, ) -> bool { match (token, reparsed_token) { (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => { @@ -492,9 +512,33 @@ pub fn tokentree_probably_equal_for_proc_macro( ( TokenTree::Delimited(_, delim, tokens), TokenTree::Delimited(_, reparsed_delim, reparsed_tokens), - ) => { - delim == reparsed_delim - && tokenstream_probably_equal_for_proc_macro(tokens, reparsed_tokens, sess) + ) if delim == reparsed_delim => tokenstream_probably_equal_for_proc_macro( + tokens, + reparsed_tokens, + sess, + relaxed_delim_match, + ), + (TokenTree::Delimited(_, DelimToken::NoDelim, tokens), reparsed_token) => { + if relaxed_delim_match { + if let TokenTree::Delimited(_, DelimToken::Paren, reparsed_tokens) = reparsed_token + { + if tokenstream_probably_equal_for_proc_macro( + tokens, + reparsed_tokens, + sess, + relaxed_delim_match, + ) { + return true; + } + } + } + tokens.len() == 1 + && tokentree_probably_equal_for_proc_macro( + &tokens.trees().next().unwrap(), + reparsed_token, + sess, + relaxed_delim_match, + ) } _ => false, } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 0eac04df3c9..17cbaf65420 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{BytePos, Pos}; use std::mem; use tracing::debug; @@ -245,11 +246,7 @@ impl<'a> Parser<'a> { this.parse_assoc_expr_with(prec + prec_adjustment, LhsExpr::NotYetParsed) })?; - // Make sure that the span of the parent node is larger than the span of lhs and rhs, - // including the attributes. - let lhs_span = - lhs.attrs.iter().find(|a| a.style == AttrStyle::Outer).map_or(lhs_span, |a| a.span); - let span = lhs_span.to(rhs.span); + let span = self.mk_expr_sp(&lhs, lhs_span, rhs.span); lhs = match op { AssocOp::Add | AssocOp::Subtract @@ -410,7 +407,7 @@ impl<'a> Parser<'a> { None }; let rhs_span = rhs.as_ref().map_or(cur_op_span, |x| x.span); - let span = lhs.span.to(rhs_span); + let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span); let limits = if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed }; Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits)?, AttrVec::new())) @@ -570,7 +567,11 @@ impl<'a> Parser<'a> { expr_kind: fn(P<Expr>, P<Ty>) -> ExprKind, ) -> PResult<'a, P<Expr>> { let mk_expr = |this: &mut Self, rhs: P<Ty>| { - this.mk_expr(lhs_span.to(rhs.span), expr_kind(lhs, rhs), AttrVec::new()) + this.mk_expr( + this.mk_expr_sp(&lhs, lhs_span, rhs.span), + expr_kind(lhs, rhs), + AttrVec::new(), + ) }; // Save the state of the parser before parsing type normally, in case there is a @@ -839,9 +840,10 @@ impl<'a> Parser<'a> { } use FloatComponent::*; + let float_str = float.as_str(); let mut components = Vec::new(); let mut ident_like = String::new(); - for c in float.as_str().chars() { + for c in float_str.chars() { if c == '_' || c.is_ascii_alphanumeric() { ident_like.push(c); } else if matches!(c, '.' | '+' | '-') { @@ -857,8 +859,13 @@ impl<'a> Parser<'a> { components.push(IdentLike(ident_like)); } - // FIXME: Make the span more precise. + // With proc macros the span can refer to anything, the source may be too short, + // or too long, or non-ASCII. It only makes sense to break our span into components + // if its underlying text is identical to our float literal. let span = self.token.span; + let can_take_span_apart = + || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref(); + match &*components { // 1e2 [IdentLike(i)] => { @@ -866,21 +873,40 @@ impl<'a> Parser<'a> { } // 1. [IdentLike(i), Punct('.')] => { + let (ident_span, dot_span) = if can_take_span_apart() { + let (span, ident_len) = (span.data(), BytePos::from_usize(i.len())); + let ident_span = span.with_hi(span.lo + ident_len); + let dot_span = span.with_lo(span.lo + ident_len); + (ident_span, dot_span) + } else { + (span, span) + }; assert!(suffix.is_none()); let symbol = Symbol::intern(&i); - self.token = Token::new(token::Ident(symbol, false), span); - let next_token = Token::new(token::Dot, span); + self.token = Token::new(token::Ident(symbol, false), ident_span); + let next_token = Token::new(token::Dot, dot_span); self.parse_tuple_field_access_expr(lo, base, symbol, None, Some(next_token)) } // 1.2 | 1.2e3 [IdentLike(i1), Punct('.'), IdentLike(i2)] => { + let (ident1_span, dot_span, ident2_span) = if can_take_span_apart() { + let (span, ident1_len) = (span.data(), BytePos::from_usize(i1.len())); + let ident1_span = span.with_hi(span.lo + ident1_len); + let dot_span = span + .with_lo(span.lo + ident1_len) + .with_hi(span.lo + ident1_len + BytePos(1)); + let ident2_span = self.token.span.with_lo(span.lo + ident1_len + BytePos(1)); + (ident1_span, dot_span, ident2_span) + } else { + (span, span, span) + }; let symbol1 = Symbol::intern(&i1); - self.token = Token::new(token::Ident(symbol1, false), span); - let next_token1 = Token::new(token::Dot, span); + self.token = Token::new(token::Ident(symbol1, false), ident1_span); + let next_token1 = Token::new(token::Dot, dot_span); let base1 = self.parse_tuple_field_access_expr(lo, base, symbol1, None, Some(next_token1)); let symbol2 = Symbol::intern(&i2); - let next_token2 = Token::new(token::Ident(symbol2, false), span); + let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span); self.bump_with(next_token2); // `.` self.parse_tuple_field_access_expr(lo, base1, symbol2, suffix, None) } @@ -2298,4 +2324,14 @@ impl<'a> Parser<'a> { pub(super) fn mk_expr_err(&self, span: Span) -> P<Expr> { self.mk_expr(span, ExprKind::Err, AttrVec::new()) } + + /// Create expression span ensuring the span of the parent node + /// is larger than the span of lhs and rhs, including the attributes. + fn mk_expr_sp(&self, lhs: &P<Expr>, lhs_span: Span, rhs_span: Span) -> Span { + lhs.attrs + .iter() + .find(|a| a.style == AttrStyle::Outer) + .map_or(lhs_span, |a| a.span) + .to(rhs_span) + } } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 26ca9980127..48341f71d33 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1744,7 +1744,7 @@ impl<'a> Parser<'a> { } }; - let span = lo.to(self.token.span); + let span = lo.until(self.token.span); Ok(Param { attrs: attrs.into(), diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 59955b27334..1acaa4c6eff 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -287,8 +287,9 @@ impl CheckAttrVisitor<'tcx> { self.doc_alias_str_error(meta); return false; } - if let Some(c) = - doc_alias.chars().find(|&c| c == '"' || c == '\'' || c.is_whitespace()) + if let Some(c) = doc_alias + .chars() + .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' ')) { self.tcx .sess @@ -302,6 +303,16 @@ impl CheckAttrVisitor<'tcx> { .emit(); return false; } + if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') { + self.tcx + .sess + .struct_span_err( + meta.span(), + "`#[doc(alias = \"...\")]` cannot start or end with ' '", + ) + .emit(); + return false; + } if let Some(err) = match target { Target::Impl => Some("implementation block"), Target::ForeignMod => Some("extern block"), diff --git a/compiler/rustc_passes/src/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs index 79f1c2b9da8..956be925be8 100644 --- a/compiler/rustc_passes/src/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -143,7 +143,7 @@ impl ExprVisitor<'tcx> { ) -> Option<InlineAsmType> { // Check the type against the allowed types for inline asm. let ty = self.typeck_results.expr_ty_adjusted(expr); - let asm_ty_isize = match self.tcx.sess.target.ptr_width { + let asm_ty_isize = match self.tcx.sess.target.pointer_width { 16 => InlineAsmType::I16, 32 => InlineAsmType::I32, 64 => InlineAsmType::I64, @@ -184,7 +184,7 @@ impl ExprVisitor<'tcx> { Some(InlineAsmType::VecI128(fields.len() as u64)) } ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => { - Some(match self.tcx.sess.target.ptr_width { + Some(match self.tcx.sess.target.pointer_width { 16 => InlineAsmType::VecI16(fields.len() as u64), 32 => InlineAsmType::VecI32(fields.len() as u64), 64 => InlineAsmType::VecI64(fields.len() as u64), diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 1378b0d5705..c9497f2a5b2 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -13,15 +13,13 @@ use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Varian use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{DeprecationEntry, Index}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{self, query::Providers, TyCtxt}; use rustc_session::lint; use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; -use rustc_trait_selection::traits::misc::can_type_implement_copy; +use rustc_span::{Span, DUMMY_SP}; use std::cmp::Ordering; use std::mem::replace; @@ -711,27 +709,35 @@ impl Visitor<'tcx> for Checker<'tcx> { // so semi-randomly perform it here in stability.rs hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => { let def_id = self.tcx.hir().local_def_id(item.hir_id); - let adt_def = self.tcx.adt_def(def_id); let ty = self.tcx.type_of(def_id); + let (adt_def, substs) = match ty.kind() { + ty::Adt(adt_def, substs) => (adt_def, substs), + _ => bug!(), + }; - if adt_def.has_dtor(self.tcx) { - feature_err( - &self.tcx.sess.parse_sess, - sym::untagged_unions, - item.span, - "unions with `Drop` implementations are unstable", - ) - .emit(); - } else { - let param_env = self.tcx.param_env(def_id); - if can_type_implement_copy(self.tcx, param_env, ty).is_err() { - feature_err( - &self.tcx.sess.parse_sess, - sym::untagged_unions, - item.span, - "unions with non-`Copy` fields are unstable", - ) - .emit(); + // Non-`Copy` fields are unstable, except for `ManuallyDrop`. + let param_env = self.tcx.param_env(def_id); + for field in &adt_def.non_enum_variant().fields { + let field_ty = field.ty(self.tcx, substs); + if !field_ty.ty_adt_def().map_or(false, |adt_def| adt_def.is_manually_drop()) + && !field_ty.is_copy_modulo_regions(self.tcx.at(DUMMY_SP), param_env) + { + if field_ty.needs_drop(self.tcx, param_env) { + // Avoid duplicate error: This will error later anyway because fields + // that need drop are not allowed. + self.tcx.sess.delay_span_bug( + item.span, + "union should have been rejected due to potentially dropping field", + ); + } else { + feature_err( + &self.tcx.sess.parse_sess, + sym::untagged_unions, + self.tcx.def_span(field.did), + "unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable", + ) + .emit(); + } } } } diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index effb25b0224..8650ee05d37 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -26,7 +26,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem if items.eh_personality().is_none() { items.missing.push(LangItem::EhPersonality); } - if tcx.sess.target.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() { + if tcx.sess.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() { items.missing.push(LangItem::EhCatchTypeinfo); } diff --git a/compiler/rustc_query_system/src/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs index e302784cc3e..7808a28dff0 100644 --- a/compiler/rustc_query_system/src/dep_graph/dep_node.rs +++ b/compiler/rustc_query_system/src/dep_graph/dep_node.rs @@ -165,10 +165,6 @@ impl WorkProductId { cgu_name.hash(&mut hasher); WorkProductId { hash: hasher.finish() } } - - pub fn from_fingerprint(fingerprint: Fingerprint) -> WorkProductId { - WorkProductId { hash: fingerprint } - } } impl<HCX> HashStable<HCX> for WorkProductId { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index d70306b4869..85335f0ba50 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -402,11 +402,6 @@ impl<K: DepKind> DepGraph<K> { self.data.as_ref().unwrap().previous.fingerprint_of(dep_node) } - #[inline] - pub fn prev_dep_node_index_of(&self, dep_node: &DepNode<K>) -> SerializedDepNodeIndex { - self.data.as_ref().unwrap().previous.node_to_index(dep_node) - } - /// Checks whether a previous work product exists for `v` and, if /// so, return the path that leads to it. Used to skip doing work. pub fn previous_work_product(&self, v: &WorkProductId) -> Option<WorkProduct> { diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs index fb313d2658f..a27b716b95a 100644 --- a/compiler/rustc_query_system/src/dep_graph/query.rs +++ b/compiler/rustc_query_system/src/dep_graph/query.rs @@ -1,7 +1,5 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::implementation::{ - Direction, Graph, NodeIndex, INCOMING, OUTGOING, -}; +use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING}; use super::{DepKind, DepNode}; @@ -52,23 +50,8 @@ impl<K: DepKind> DepGraphQuery<K> { } } - /// All nodes reachable from `node`. In other words, things that - /// will have to be recomputed if `node` changes. - pub fn transitive_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> { - self.reachable_nodes(node, OUTGOING) - } - /// All nodes that can reach `node`. pub fn transitive_predecessors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> { self.reachable_nodes(node, INCOMING) } - - /// Just the outgoing edges from `node`. - pub fn immediate_successors(&self, node: &DepNode<K>) -> Vec<&DepNode<K>> { - if let Some(&index) = self.indices.get(&node) { - self.graph.successor_nodes(index).map(|s| self.graph.node_data(s)).collect() - } else { - vec![] - } - } } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index e3cf6d12bd5..33ab09a8f42 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -469,24 +469,17 @@ impl<'a> Resolver<'a> { ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => { let mut err = self.session.struct_span_err( span, - "generic parameters must not be used inside of non-trivial constant values", - ); - err.span_label( - span, - &format!( - "non-trivial anonymous constants must not depend on the parameter `{}`", - name - ), + "generic parameters may not be used in const operations", ); + err.span_label(span, &format!("cannot perform const operation using `{}`", name)); if is_type { - err.note("type parameters are currently not permitted in anonymous constants"); + err.note("type parameters may not be used in const expressions"); } else { - err.help( - &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", - name - ) - ); + err.help(&format!( + "const parameters may only be used as standalone arguments, i.e. `{}`", + name + )); } err @@ -929,6 +922,17 @@ impl<'a> Resolver<'a> { ); self.add_typo_suggestion(err, suggestion, ident.span); + let import_suggestions = self.lookup_import_candidates( + ident, + Namespace::MacroNS, + parent_scope, + |res| match res { + Res::Def(DefKind::Macro(MacroKind::Bang), _) => true, + _ => false, + }, + ); + show_candidates(err, None, &import_suggestions, false, true); + if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) { let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident); err.span_note(ident.span, &msg); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2c01934b490..219517b4ab2 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -384,6 +384,13 @@ struct DiagnosticMetadata<'ast> { /// Used to detect possible `if let` written without `let` and to provide structured suggestion. in_if_condition: Option<&'ast Expr>, + + /// If we are currently in a trait object definition. Used to point at the bounds when + /// encountering a struct or enum. + current_trait_object: Option<&'ast [ast::GenericBound]>, + + /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`. + current_where_predicate: Option<&'ast WherePredicate>, } struct LateResolutionVisitor<'a, 'b, 'ast> { @@ -453,6 +460,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.diagnostic_metadata.current_let_binding = original; } fn visit_ty(&mut self, ty: &'ast Ty) { + let prev = self.diagnostic_metadata.current_trait_object; match ty.kind { TyKind::Path(ref qself, ref path) => { self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type); @@ -464,9 +472,13 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { .map_or(Res::Err, |d| d.res()); self.r.record_partial_res(ty.id, PartialRes::new(res)); } + TyKind::TraitObject(ref bounds, ..) => { + self.diagnostic_metadata.current_trait_object = Some(&bounds[..]); + } _ => (), } visit::walk_ty(self, ty); + self.diagnostic_metadata.current_trait_object = prev; } fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { self.smart_resolve_path( @@ -660,6 +672,14 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } self.diagnostic_metadata.currently_processing_generics = prev; } + + fn visit_where_predicate(&mut self, p: &'ast WherePredicate) { + debug!("visit_where_predicate {:?}", p); + let previous_value = + replace(&mut self.diagnostic_metadata.current_where_predicate, Some(p)); + visit::walk_where_predicate(self, p); + self.diagnostic_metadata.current_where_predicate = previous_value; + } } impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 15e72228870..c24b383f3b8 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1,6 +1,6 @@ use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion}; use crate::late::lifetimes::{ElisionFailureInfo, LifetimeContext}; -use crate::late::{LateResolutionVisitor, RibKind}; +use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind}; use crate::path_names_to_string; use crate::{CrateLint, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{PathResult, PathSource, Segment}; @@ -8,6 +8,7 @@ use crate::{PathResult, PathSource, Segment}; use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_ast::visit::FnKind; use rustc_ast::{self as ast, Expr, ExprKind, Item, ItemKind, NodeId, Path, Ty, TyKind}; +use rustc_ast_pretty::pprust::path_segment_to_string; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -19,7 +20,7 @@ use rustc_session::config::nightly_options; use rustc_session::parse::feature_err; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use tracing::debug; @@ -439,27 +440,213 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { } } - if !self.type_ascription_suggestion(&mut err, base_span) - && !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) - { - // Fallback label. - err.span_label(base_span, fallback_label); - - match self.diagnostic_metadata.current_let_binding { - Some((pat_sp, Some(ty_sp), None)) if ty_sp.contains(base_span) && could_be_expr => { - err.span_suggestion_short( - pat_sp.between(ty_sp), - "use `=` if you meant to assign", - " = ".to_string(), - Applicability::MaybeIncorrect, + if !self.type_ascription_suggestion(&mut err, base_span) { + let mut fallback = false; + if let ( + PathSource::Trait(AliasPossibility::Maybe), + Some(Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, _)), + ) = (source, res) + { + if let Some(bounds @ [_, .., _]) = self.diagnostic_metadata.current_trait_object { + fallback = true; + let spans: Vec<Span> = bounds + .iter() + .map(|bound| bound.span()) + .filter(|&sp| sp != base_span) + .collect(); + + let start_span = bounds.iter().map(|bound| bound.span()).next().unwrap(); + // `end_span` is the end of the poly trait ref (Foo + 'baz + Bar><) + let end_span = bounds.iter().map(|bound| bound.span()).last().unwrap(); + // `last_bound_span` is the last bound of the poly trait ref (Foo + >'baz< + Bar) + let last_bound_span = spans.last().cloned().unwrap(); + let mut multi_span: MultiSpan = spans.clone().into(); + for sp in spans { + let msg = if sp == last_bound_span { + format!( + "...because of {} bound{}", + if bounds.len() <= 2 { "this" } else { "these" }, + if bounds.len() <= 2 { "" } else { "s" }, + ) + } else { + String::new() + }; + multi_span.push_span_label(sp, msg); + } + multi_span.push_span_label( + base_span, + "expected this type to be a trait...".to_string(), ); + err.span_help( + multi_span, + "`+` is used to constrain a \"trait object\" type with lifetimes or \ + auto-traits; structs and enums can't be bound in that way", + ); + if bounds.iter().all(|bound| match bound { + ast::GenericBound::Outlives(_) => true, + ast::GenericBound::Trait(tr, _) => tr.span == base_span, + }) { + let mut sugg = vec![]; + if base_span != start_span { + sugg.push((start_span.until(base_span), String::new())); + } + if base_span != end_span { + sugg.push((base_span.shrink_to_hi().to(end_span), String::new())); + } + + err.multipart_suggestion( + "if you meant to use a type and not a trait here, remove the bounds", + sugg, + Applicability::MaybeIncorrect, + ); + } } - _ => {} + } + + fallback |= self.restrict_assoc_type_in_where_clause(span, &mut err); + + if !self.r.add_typo_suggestion(&mut err, typo_sugg, ident_span) { + fallback = true; + match self.diagnostic_metadata.current_let_binding { + Some((pat_sp, Some(ty_sp), None)) + if ty_sp.contains(base_span) && could_be_expr => + { + err.span_suggestion_short( + pat_sp.between(ty_sp), + "use `=` if you meant to assign", + " = ".to_string(), + Applicability::MaybeIncorrect, + ); + } + _ => {} + } + } + if fallback { + // Fallback label. + err.span_label(base_span, fallback_label); } } (err, candidates) } + /// Given `where <T as Bar>::Baz: String`, suggest `where T: Bar<Baz = String>`. + fn restrict_assoc_type_in_where_clause( + &mut self, + span: Span, + err: &mut DiagnosticBuilder<'_>, + ) -> bool { + // Detect that we are actually in a `where` predicate. + let (bounded_ty, bounds, where_span) = + if let Some(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate { + bounded_ty, + bound_generic_params, + bounds, + span, + })) = self.diagnostic_metadata.current_where_predicate + { + if !bound_generic_params.is_empty() { + return false; + } + (bounded_ty, bounds, span) + } else { + return false; + }; + + // Confirm that the target is an associated type. + let (ty, position, path) = if let ast::TyKind::Path( + Some(ast::QSelf { ty, position, .. }), + path, + ) = &bounded_ty.kind + { + // use this to verify that ident is a type param. + let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere( + bounded_ty.id, + None, + &Segment::from_path(path), + Namespace::TypeNS, + span, + true, + CrateLint::No, + ) { + partial_res + } else { + return false; + }; + if !(matches!( + partial_res.base_res(), + hir::def::Res::Def(hir::def::DefKind::AssocTy, _) + ) && partial_res.unresolved_segments() == 0) + { + return false; + } + (ty, position, path) + } else { + return false; + }; + + if let ast::TyKind::Path(None, type_param_path) = &ty.peel_refs().kind { + // Confirm that the `SelfTy` is a type parameter. + let partial_res = if let Ok(Some(partial_res)) = self.resolve_qpath_anywhere( + bounded_ty.id, + None, + &Segment::from_path(type_param_path), + Namespace::TypeNS, + span, + true, + CrateLint::No, + ) { + partial_res + } else { + return false; + }; + if !(matches!( + partial_res.base_res(), + hir::def::Res::Def(hir::def::DefKind::TyParam, _) + ) && partial_res.unresolved_segments() == 0) + { + return false; + } + if let ( + [ast::PathSegment { ident: constrain_ident, args: None, .. }], + [ast::GenericBound::Trait(poly_trait_ref, ast::TraitBoundModifier::None)], + ) = (&type_param_path.segments[..], &bounds[..]) + { + if let [ast::PathSegment { ident, args: None, .. }] = + &poly_trait_ref.trait_ref.path.segments[..] + { + if ident.span == span { + err.span_suggestion_verbose( + *where_span, + &format!("constrain the associated type to `{}`", ident), + format!( + "{}: {}<{} = {}>", + self.r + .session + .source_map() + .span_to_snippet(ty.span) // Account for `<&'a T as Foo>::Bar`. + .unwrap_or_else(|_| constrain_ident.to_string()), + path.segments[..*position] + .iter() + .map(|segment| path_segment_to_string(segment)) + .collect::<Vec<_>>() + .join("::"), + path.segments[*position..] + .iter() + .map(|segment| path_segment_to_string(segment)) + .collect::<Vec<_>>() + .join("::"), + ident, + ), + Applicability::MaybeIncorrect, + ); + } + return true; + } + } + } + false + } + /// Check if the source is call expression and the first argument is `self`. If true, /// return the span of whole call and the span for all arguments expect the first one (`self`). fn call_has_self_arg(&self, source: PathSource<'_>) -> Option<(Span, Option<Span>)> { @@ -1143,58 +1330,17 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { let suggest_only_tuple_variants = matches!(source, PathSource::TupleStruct(..)) || source.is_call(); - let mut suggestable_variants = if suggest_only_tuple_variants { + if suggest_only_tuple_variants { // Suggest only tuple variants regardless of whether they have fields and do not // suggest path with added parenthesis. - variants + let mut suggestable_variants = variants .iter() .filter(|(.., kind)| *kind == CtorKind::Fn) .map(|(variant, ..)| path_names_to_string(variant)) - .collect::<Vec<_>>() - } else { - variants - .iter() - .filter(|(_, def_id, kind)| { - // Suggest only variants that have no fields (these can definitely - // be constructed). - let has_fields = - self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false); - match kind { - CtorKind::Const => true, - CtorKind::Fn | CtorKind::Fictive if has_fields => true, - _ => false, - } - }) - .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) - .map(|(variant_str, kind)| { - // Add constructor syntax where appropriate. - match kind { - CtorKind::Const => variant_str, - CtorKind::Fn => format!("({}())", variant_str), - CtorKind::Fictive => format!("({} {{}})", variant_str), - } - }) - .collect::<Vec<_>>() - }; - - let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); + .collect::<Vec<_>>(); - if !suggestable_variants.is_empty() { - let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { - "try using the enum's variant" - } else { - "try using one of the enum's variants" - }; + let non_suggestable_variant_count = variants.len() - suggestable_variants.len(); - err.span_suggestions( - span, - msg, - suggestable_variants.drain(..), - Applicability::MaybeIncorrect, - ); - } - - if suggest_only_tuple_variants { let source_msg = if source.is_call() { "to construct" } else if matches!(source, PathSource::TupleStruct(..)) { @@ -1203,6 +1349,21 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { unreachable!() }; + if !suggestable_variants.is_empty() { + let msg = if non_suggestable_variant_count == 0 && suggestable_variants.len() == 1 { + format!("try {} the enum's variant", source_msg) + } else { + format!("try {} one of the enum's variants", source_msg) + }; + + err.span_suggestions( + span, + &msg, + suggestable_variants.drain(..), + Applicability::MaybeIncorrect, + ); + } + // If the enum has no tuple variants.. if non_suggestable_variant_count == variants.len() { err.help(&format!("the enum has no tuple variants {}", source_msg)); @@ -1221,24 +1382,76 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { )); } } else { - let made_suggestion = non_suggestable_variant_count != variants.len(); - if made_suggestion { - if non_suggestable_variant_count == 1 { - err.help( - "you might have meant to use the enum's other variant that has fields", - ); - } else if non_suggestable_variant_count >= 1 { - err.help( - "you might have meant to use one of the enum's other variants that \ - have fields", - ); - } - } else { - if non_suggestable_variant_count == 1 { - err.help("you might have meant to use the enum's variant"); - } else if non_suggestable_variant_count >= 1 { - err.help("you might have meant to use one of the enum's variants"); + let needs_placeholder = |def_id: DefId, kind: CtorKind| { + let has_no_fields = + self.r.field_names.get(&def_id).map(|f| f.is_empty()).unwrap_or(false); + match kind { + CtorKind::Const => false, + CtorKind::Fn | CtorKind::Fictive if has_no_fields => false, + _ => true, } + }; + + let mut suggestable_variants = variants + .iter() + .filter(|(_, def_id, kind)| !needs_placeholder(*def_id, *kind)) + .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) + .map(|(variant, kind)| match kind { + CtorKind::Const => variant, + CtorKind::Fn => format!("({}())", variant), + CtorKind::Fictive => format!("({} {{}})", variant), + }) + .collect::<Vec<_>>(); + + if !suggestable_variants.is_empty() { + let msg = if suggestable_variants.len() == 1 { + "you might have meant to use the following enum variant" + } else { + "you might have meant to use one of the following enum variants" + }; + + err.span_suggestions( + span, + msg, + suggestable_variants.drain(..), + Applicability::MaybeIncorrect, + ); + } + + let mut suggestable_variants_with_placeholders = variants + .iter() + .filter(|(_, def_id, kind)| needs_placeholder(*def_id, *kind)) + .map(|(variant, _, kind)| (path_names_to_string(variant), kind)) + .filter_map(|(variant, kind)| match kind { + CtorKind::Fn => Some(format!("({}(/* fields */))", variant)), + CtorKind::Fictive => Some(format!("({} {{ /* fields */ }})", variant)), + _ => None, + }) + .collect::<Vec<_>>(); + + if !suggestable_variants_with_placeholders.is_empty() { + let msg = match ( + suggestable_variants.is_empty(), + suggestable_variants_with_placeholders.len(), + ) { + (true, 1) => "the following enum variant is available", + (true, _) => "the following enum variants are available", + (false, 1) => "alternatively, the following enum variant is available", + (false, _) => "alternatively, the following enum variants are also available", + }; + + err.span_suggestions( + span, + msg, + suggestable_variants_with_placeholders.drain(..), + Applicability::HasPlaceholders, + ); + } + }; + + if def_id.is_local() { + if let Some(span) = self.def_span(def_id) { + err.span_note(span, "the enum is defined here"); } } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index fe8f5926385..6677a5ffe28 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -218,7 +218,7 @@ enum ResolutionError<'a> { ParamInTyOfConstParam(Symbol), /// constant values inside of type parameter defaults must not depend on generic parameters. ParamInAnonConstInTyDefault(Symbol), - /// generic parameters must not be used inside of non-trivial constant values. + /// generic parameters must not be used inside const evaluations. /// /// This error is only emitted when using `min_const_generics`. ParamInNonTrivialAnonConst { name: Symbol, is_type: bool }, diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index fa4423e261d..8b79c93e760 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -107,7 +107,7 @@ impl serialize::Encoder for Encoder { #[inline] fn emit_i8(&mut self, v: i8) -> EncodeResult { - let as_u8: u8 = unsafe { ::std::mem::transmute(v) }; + let as_u8: u8 = unsafe { std::mem::transmute(v) }; self.emit_u8(as_u8) } @@ -300,13 +300,13 @@ impl<'a> serialize::Decoder for Decoder<'a> { #[inline] fn read_char(&mut self) -> Result<char, Self::Error> { let bits = self.read_u32()?; - Ok(::std::char::from_u32(bits).unwrap()) + Ok(std::char::from_u32(bits).unwrap()) } #[inline] fn read_str(&mut self) -> Result<Cow<'_, str>, Self::Error> { let len = self.read_usize()?; - let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap(); + let s = std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap(); self.position += len; Ok(Cow::Borrowed(s)) } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 231e315a22f..f33bebf99d6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -34,11 +34,6 @@ use std::iter::{self, FromIterator}; use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; -pub struct Config { - pub target: Target, - pub ptr_width: u32, -} - bitflags! { #[derive(Default, Encodable, Decodable)] pub struct SanitizerSet: u8 { @@ -740,16 +735,16 @@ pub const fn default_lib_output() -> CrateType { } pub fn default_configuration(sess: &Session) -> CrateConfig { - let end = &sess.target.target.target_endian; - let arch = &sess.target.target.arch; - let wordsz = &sess.target.target.target_pointer_width; - let os = &sess.target.target.target_os; - let env = &sess.target.target.target_env; - let vendor = &sess.target.target.target_vendor; - let min_atomic_width = sess.target.target.min_atomic_width(); - let max_atomic_width = sess.target.target.max_atomic_width(); - let atomic_cas = sess.target.target.options.atomic_cas; - let layout = TargetDataLayout::parse(&sess.target.target).unwrap_or_else(|err| { + let end = &sess.target.target_endian; + let arch = &sess.target.arch; + let wordsz = sess.target.pointer_width.to_string(); + let os = &sess.target.target_os; + let env = &sess.target.target_env; + let vendor = &sess.target.target_vendor; + let min_atomic_width = sess.target.min_atomic_width(); + let max_atomic_width = sess.target.max_atomic_width(); + let atomic_cas = sess.target.options.atomic_cas; + let layout = TargetDataLayout::parse(&sess.target).unwrap_or_else(|err| { sess.fatal(&err); }); @@ -757,7 +752,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { ret.reserve(6); // the minimum number of insertions // Target bindings. ret.insert((sym::target_os, Some(Symbol::intern(os)))); - if let Some(ref fam) = sess.target.target.options.target_family { + if let Some(ref fam) = sess.target.options.target_family { ret.insert((sym::target_family, Some(Symbol::intern(fam)))); if fam == "windows" { ret.insert((sym::windows, None)); @@ -767,10 +762,10 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { } ret.insert((sym::target_arch, Some(Symbol::intern(arch)))); ret.insert((sym::target_endian, Some(Symbol::intern(end)))); - ret.insert((sym::target_pointer_width, Some(Symbol::intern(wordsz)))); + ret.insert((sym::target_pointer_width, Some(Symbol::intern(&wordsz)))); ret.insert((sym::target_env, Some(Symbol::intern(env)))); ret.insert((sym::target_vendor, Some(Symbol::intern(vendor)))); - if sess.target.target.options.has_elf_tls { + if sess.target.options.has_elf_tls { ret.insert((sym::target_thread_local, None)); } for &(i, align) in &[ @@ -792,7 +787,7 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { }; let s = i.to_string(); insert_atomic(&s, align); - if &s == wordsz { + if s == wordsz { insert_atomic("ptr", layout.pointer_align.abi); } } @@ -831,7 +826,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo user_cfg } -pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Config { +pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> Target { let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok); let target = target_result.unwrap_or_else(|e| { early_error( @@ -844,21 +839,18 @@ pub fn build_target_config(opts: &Options, target_override: Option<Target>) -> C ) }); - let ptr_width = match &target.target_pointer_width[..] { - "16" => 16, - "32" => 32, - "64" => 64, - w => early_error( + if !matches!(target.pointer_width, 16 | 32 | 64) { + early_error( opts.error_format, &format!( "target specification was invalid: \ unrecognized target-pointer-width {}", - w + target.pointer_width ), - ), - }; + ) + } - Config { target, ptr_width } + target } #[derive(Copy, Clone, PartialEq, Eq, Debug)] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index a106007c274..627adcceb3f 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1078,6 +1078,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show extended diagnostic help (default: no)"), terminal_width: Option<usize> = (None, parse_opt_uint, [UNTRACKED], "set the current terminal width"), + tune_cpu: Option<String> = (None, parse_opt_string, [TRACKED], + "select processor to schedule for (`rustc --print target-cpus` for details)"), thinlto: Option<bool> = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), // We default to 1 here since we want to behave like diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index bf9c96c6c94..0766c55da74 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -151,18 +151,16 @@ pub fn filename_for_input( CrateType::Rlib => outputs.out_directory.join(&format!("lib{}.rlib", libname)), CrateType::Cdylib | CrateType::ProcMacro | CrateType::Dylib => { let (prefix, suffix) = - (&sess.target.target.options.dll_prefix, &sess.target.target.options.dll_suffix); + (&sess.target.options.dll_prefix, &sess.target.options.dll_suffix); outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix)) } CrateType::Staticlib => { - let (prefix, suffix) = ( - &sess.target.target.options.staticlib_prefix, - &sess.target.target.options.staticlib_suffix, - ); + let (prefix, suffix) = + (&sess.target.options.staticlib_prefix, &sess.target.options.staticlib_suffix); outputs.out_directory.join(&format!("{}{}{}", prefix, libname, suffix)) } CrateType::Executable => { - let suffix = &sess.target.target.options.exe_suffix; + let suffix = &sess.target.options.exe_suffix; let out_filename = outputs.path(OutputType::Exe); if suffix.is_empty() { out_filename } else { out_filename.with_extension(&suffix[1..]) } } @@ -179,35 +177,29 @@ pub fn filename_for_input( /// interaction with Rust code through static library is the only /// option for now pub fn default_output_for_target(sess: &Session) -> CrateType { - if !sess.target.target.options.executables { - CrateType::Staticlib - } else { - CrateType::Executable - } + if !sess.target.options.executables { CrateType::Staticlib } else { CrateType::Executable } } /// Checks if target supports crate_type as output pub fn invalid_output_for_target(sess: &Session, crate_type: CrateType) -> bool { match crate_type { CrateType::Cdylib | CrateType::Dylib | CrateType::ProcMacro => { - if !sess.target.target.options.dynamic_linking { + if !sess.target.options.dynamic_linking { return true; } - if sess.crt_static(Some(crate_type)) - && !sess.target.target.options.crt_static_allows_dylibs - { + if sess.crt_static(Some(crate_type)) && !sess.target.options.crt_static_allows_dylibs { return true; } } _ => {} } - if sess.target.target.options.only_cdylib { + if sess.target.options.only_cdylib { match crate_type { CrateType::ProcMacro | CrateType::Dylib => return true, _ => {} } } - if !sess.target.target.options.executables { + if !sess.target.options.executables { if crate_type == CrateType::Executable { return true; } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index ff5e6156d84..8312f89b271 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -102,7 +102,7 @@ impl Mul<usize> for Limit { /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { - pub target: config::Config, + pub target: Target, pub host: Target, pub opts: config::Options, pub host_tlib_path: SearchPath, @@ -614,7 +614,7 @@ impl Session { /// Calculates the flavor of LTO to use for this compilation. pub fn lto(&self) -> config::Lto { // If our target has codegen requirements ignore the command line - if self.target.target.options.requires_lto { + if self.target.options.requires_lto { return config::Lto::Fat; } @@ -682,7 +682,7 @@ impl Session { /// Returns the panic strategy for this compile session. If the user explicitly selected one /// using '-C panic', use that, otherwise use the panic strategy defined by the target. pub fn panic_strategy(&self) -> PanicStrategy { - self.opts.cg.panic.unwrap_or(self.target.target.options.panic_strategy) + self.opts.cg.panic.unwrap_or(self.target.options.panic_strategy) } pub fn fewer_names(&self) -> bool { let more_names = self.opts.output_types.contains_key(&OutputType::LlvmAssembly) @@ -706,9 +706,9 @@ impl Session { /// Check whether this compile session and crate type use static crt. pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool { - if !self.target.target.options.crt_static_respected { + if !self.target.options.crt_static_respected { // If the target does not opt in to crt-static support, use its default. - return self.target.target.options.crt_static_default; + return self.target.options.crt_static_default; } let requested_features = self.opts.cg.target_feature.split(','); @@ -725,20 +725,20 @@ impl Session { // We can't check `#![crate_type = "proc-macro"]` here. false } else { - self.target.target.options.crt_static_default + self.target.options.crt_static_default } } pub fn relocation_model(&self) -> RelocModel { - self.opts.cg.relocation_model.unwrap_or(self.target.target.options.relocation_model) + self.opts.cg.relocation_model.unwrap_or(self.target.options.relocation_model) } pub fn code_model(&self) -> Option<CodeModel> { - self.opts.cg.code_model.or(self.target.target.options.code_model) + self.opts.cg.code_model.or(self.target.options.code_model) } pub fn tls_model(&self) -> TlsModel { - self.opts.debugging_opts.tls_model.unwrap_or(self.target.target.options.tls_model) + self.opts.debugging_opts.tls_model.unwrap_or(self.target.options.tls_model) } pub fn must_not_eliminate_frame_pointers(&self) -> bool { @@ -749,7 +749,7 @@ impl Session { } else if let Some(x) = self.opts.cg.force_frame_pointers { x } else { - !self.target.target.options.eliminate_frame_pointer + !self.target.options.eliminate_frame_pointer } } @@ -773,7 +773,7 @@ impl Session { // value, if it is provided, or disable them, if not. if self.panic_strategy() == PanicStrategy::Unwind { true - } else if self.target.target.options.requires_uwtable { + } else if self.target.options.requires_uwtable { true } else { self.opts.cg.force_unwind_tables.unwrap_or(false) @@ -944,7 +944,7 @@ impl Session { if let Some(n) = self.opts.cli_forced_codegen_units { return n; } - if let Some(n) = self.target.target.options.default_codegen_units { + if let Some(n) = self.target.options.default_codegen_units { return n as usize; } @@ -1029,11 +1029,11 @@ impl Session { pub fn needs_plt(&self) -> bool { // Check if the current target usually needs PLT to be enabled. // The user can use the command line flag to override it. - let needs_plt = self.target.target.options.needs_plt; + let needs_plt = self.target.options.needs_plt; let dbg_opts = &self.opts.debugging_opts; - let relro_level = dbg_opts.relro_level.unwrap_or(self.target.target.options.relro_level); + let relro_level = dbg_opts.relro_level.unwrap_or(self.target.options.relro_level); // Only enable this optimization by default if full relro is also enabled. // In this case, lazy binding was already unavailable, so nothing is lost. @@ -1057,8 +1057,7 @@ impl Session { match self.opts.cg.link_dead_code { Some(explicitly_set) => explicitly_set, None => { - self.opts.debugging_opts.instrument_coverage - && !self.target.target.options.is_like_msvc + self.opts.debugging_opts.instrument_coverage && !self.target.options.is_like_msvc // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid // binaries when LLVM InstrProf counters are enabled). As described by this issue, // the "link dead code" option produces incorrect binaries when compiled and linked @@ -1259,7 +1258,7 @@ pub fn build_session( let loader = file_loader.unwrap_or(Box::new(RealFileLoader)); let hash_kind = sopts.debugging_opts.src_hash_algorithm.unwrap_or_else(|| { - if target_cfg.target.options.is_like_msvc { + if target_cfg.options.is_like_msvc { SourceFileHashAlgorithm::Sha1 } else { SourceFileHashAlgorithm::Md5 @@ -1369,8 +1368,8 @@ pub fn build_session( if candidate.join("library/std/src/lib.rs").is_file() { Some(candidate) } else { None } }; - let asm_arch = if target_cfg.target.options.allow_asm { - InlineAsmArch::from_str(&target_cfg.target.arch).ok() + let asm_arch = if target_cfg.options.allow_asm { + InlineAsmArch::from_str(&target_cfg.arch).ok() } else { None }; @@ -1438,7 +1437,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // the `dllimport` attributes and `__imp_` symbols in that case. if sess.opts.cg.linker_plugin_lto.enabled() && sess.opts.cg.prefer_dynamic - && sess.target.target.options.is_like_windows + && sess.target.options.is_like_windows { sess.err( "Linker plugin based LTO is not supported together with \ @@ -1466,7 +1465,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { ); } - if sess.target.target.options.requires_uwtable && !include_uwtables { + if sess.target.options.requires_uwtable && !include_uwtables { sess.err( "target requires unwind tables, they cannot be disabled with \ `-C force-unwind-tables=no`.", @@ -1481,7 +1480,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) { // We should only display this error if we're actually going to run PGO. // If we're just supposed to print out some data, don't show the error (#61002). if sess.opts.cg.profile_generate.enabled() - && sess.target.target.options.is_like_msvc + && sess.target.options.is_like_msvc && sess.panic_strategy() == PanicStrategy::Unwind && sess.opts.prints.iter().all(|&p| p == PrintRequest::NativeStaticLibs) { @@ -1586,5 +1585,3 @@ pub fn early_warn(output: config::ErrorOutputType, msg: &str) { let handler = rustc_errors::Handler::with_emitter(true, None, emitter); handler.struct_warn(msg).emit(); } - -pub type CompileResult = Result<(), ErrorReported>; diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index fb80dcb7561..31f3d8e3791 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -619,14 +619,6 @@ impl SyntaxContext { HygieneData::with(|data| data.outer_mark(self)) } - #[inline] - pub fn outer_mark_with_data(self) -> (ExpnId, Transparency, ExpnData) { - HygieneData::with(|data| { - let (expn_id, transparency) = data.outer_mark(self); - (expn_id, transparency, data.expn_data(expn_id).clone()) - }) - } - pub fn dollar_crate_name(self) -> Symbol { HygieneData::with(|data| data.syntax_context_data[self.0 as usize].dollar_crate_name) } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 925f1bd33cb..d036c078049 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -223,12 +223,6 @@ impl FileName { } } - pub fn quote_expansion_source_code(src: &str) -> FileName { - let mut hasher = StableHasher::new(); - src.hash(&mut hasher); - FileName::QuoteExpansion(hasher.finish()) - } - pub fn macro_expansion_source_code(src: &str) -> FileName { let mut hasher = StableHasher::new(); src.hash(&mut hasher); diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index fdb031fd9b3..3b929c4acb9 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -451,15 +451,6 @@ impl SourceMap { } } - /// Returns a new `Span` covering the start and end `BytePos`s of the file containing the given - /// `pos`. This can be used to quickly determine if another `BytePos` or `Span` is from the same - /// file. - pub fn lookup_file_span(&self, pos: BytePos) -> Span { - let idx = self.lookup_source_file_idx(pos); - let SourceFile { start_pos, end_pos, .. } = *(*self.files.borrow().source_files)[idx]; - Span::with_root_ctxt(start_pos, end_pos) - } - /// Returns `Some(span)`, a union of the LHS and RHS span. The LHS must precede the RHS. If /// there are gaps between LHS and RHS, the resulting union will cross these gaps. /// For this to work, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 223a0758f00..28fef65da07 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1114,6 +1114,7 @@ symbols! { try_trait, tt, tuple, + tuple_from_req, tuple_indexing, two_phase, ty, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index b96e318bd3e..2c9caf73b8e 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -115,7 +115,6 @@ fn get_symbol_hash<'tcx>( } // also include any type parameters (for generic items) - assert!(!substs.has_erasable_regions()); substs.hash_stable(&mut hcx, &mut hasher); if let Some(instantiating_crate) = instantiating_crate { diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 75150a56c43..28b4a78929e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -201,7 +201,7 @@ fn compute_symbol_name( // // [1]: https://bugs.llvm.org/show_bug.cgi?id=44316 if is_foreign { - if tcx.sess.target.target.arch != "wasm32" + if tcx.sess.target.arch != "wasm32" || !tcx.wasm_import_module_map(def_id.krate).contains_key(&def_id) { if let Some(name) = attrs.link_name { diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs index d2c9b05c560..822a8352934 100644 --- a/compiler/rustc_symbol_mangling/src/test.rs +++ b/compiler/rustc_symbol_mangling/src/test.rs @@ -6,7 +6,7 @@ use rustc_hir as hir; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{Instance, TyCtxt}; +use rustc_middle::ty::{subst::InternalSubsts, Instance, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; const SYMBOL_NAME: Symbol = sym::rustc_symbol_name; @@ -36,8 +36,11 @@ impl SymbolNamesTest<'tcx> { let def_id = tcx.hir().local_def_id(hir_id); for attr in tcx.get_attrs(def_id.to_def_id()).iter() { if tcx.sess.check_name(attr, SYMBOL_NAME) { - // for now, can only use on monomorphic names - let instance = Instance::mono(tcx, def_id.to_def_id()); + let def_id = def_id.to_def_id(); + let instance = Instance::new( + def_id, + tcx.erase_regions(&InternalSubsts::identity_for_item(tcx, def_id)), + ); let mangled = tcx.symbol_name(instance); tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled)); if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) { diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index da9c93143bf..16d0b86903e 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -132,7 +132,7 @@ impl SymbolMangler<'tcx> { self.push("u"); // FIXME(eddyb) we should probably roll our own punycode implementation. - let mut punycode_bytes = match ::punycode::encode(ident) { + let mut punycode_bytes = match punycode::encode(ident) { Ok(s) => s.into_bytes(), Err(()) => bug!("symbol_names: punycode encoding failed for ident {:?}", ident), }; @@ -259,7 +259,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } fn print_impl_path( - self, + mut self, impl_def_id: DefId, substs: &'tcx [GenericArg<'tcx>], mut self_ty: Ty<'tcx>, @@ -284,12 +284,37 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } } - self.path_append_impl( - |cx| cx.print_def_path(parent_def_id, &[]), - &key.disambiguated_data, - self_ty, - impl_trait_ref, - ) + self.push(match impl_trait_ref { + Some(_) => "X", + None => "M", + }); + + // Encode impl generic params if the substitutions contain parameters (implying + // polymorphization is enabled) and this isn't an inherent impl. + if impl_trait_ref.is_some() && substs.iter().any(|a| a.has_param_types_or_consts()) { + self = self.path_generic_args( + |this| { + this.path_append_ns( + |cx| cx.print_def_path(parent_def_id, &[]), + 'I', + key.disambiguated_data.disambiguator as u64, + "", + ) + }, + substs, + )?; + } else { + self.push_disambiguator(key.disambiguated_data.disambiguator as u64); + self = self.print_def_path(parent_def_id, &[])?; + } + + self = self_ty.print(self)?; + + if let Some(trait_ref) = impl_trait_ref { + self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; + } + + Ok(self) } fn print_region(mut self, region: ty::Region<'_>) -> Result<Self::Region, Self::Error> { @@ -538,6 +563,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { self.push_ident(&name); Ok(self) } + fn path_qualified( mut self, self_ty: Ty<'tcx>, @@ -552,24 +578,16 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } fn path_append_impl( - mut self, - print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, - disambiguated_data: &DisambiguatedDefPathData, - self_ty: Ty<'tcx>, - trait_ref: Option<ty::TraitRef<'tcx>>, + self, + _: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, + _: &DisambiguatedDefPathData, + _: Ty<'tcx>, + _: Option<ty::TraitRef<'tcx>>, ) -> Result<Self::Path, Self::Error> { - self.push(match trait_ref { - Some(_) => "X", - None => "M", - }); - self.push_disambiguator(disambiguated_data.disambiguator as u64); - self = print_prefix(self)?; - self = self_ty.print(self)?; - if let Some(trait_ref) = trait_ref { - self = self.print_def_path(trait_ref.def_id, trait_ref.substs)?; - } - Ok(self) + // Inlined into `print_impl_path` + unreachable!() } + fn path_append( self, print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, @@ -603,6 +621,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { name.as_ref().map_or("", |s| &s[..]), ) } + fn path_generic_args( mut self, print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>, diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index 3c1a2ea39d3..047b8cf5cdb 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -164,12 +164,12 @@ impl TargetDataLayout { )); } - if dl.pointer_size.bits().to_string() != target.target_pointer_width { + if dl.pointer_size.bits() != target.pointer_width.into() { return Err(format!( "inconsistent target specification: \"data-layout\" claims \ pointers are {}-bit, while \"target-pointer-width\" is `{}`", dl.pointer_size.bits(), - target.target_pointer_width + target.pointer_width )); } diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs index 638c52d97f1..b19489aa439 100644 --- a/compiler/rustc_target/src/asm/mips.rs +++ b/compiler/rustc_target/src/asm/mips.rs @@ -32,11 +32,12 @@ impl MipsInlineAsmRegClass { pub fn supported_types( self, - _arch: InlineAsmArch, + arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option<&'static str>)] { - match self { - Self::reg => types! { _: I8, I16, I32, F32; }, - Self::freg => types! { _: F32; }, + match (self, arch) { + (Self::reg, InlineAsmArch::Mips64) => types! { _: I8, I16, I32, I64, F32, F64; }, + (Self::reg, _) => types! { _: I8, I16, I32, F32; }, + (Self::freg, _) => types! { _: F32, F64; }, } } } @@ -44,31 +45,31 @@ impl MipsInlineAsmRegClass { // The reserved registers are somewhat taken from <https://git.io/JUR1k#L150>. def_regs! { Mips MipsInlineAsmReg MipsInlineAsmRegClass { - v0: reg = ["$2", "$v0"], - v1: reg = ["$3", "$v1"], - a0: reg = ["$4", "$a0"], - a1: reg = ["$5", "$a1"], - a2: reg = ["$6", "$a2"], - a3: reg = ["$7", "$a3"], + r2: reg = ["$2"], + r3: reg = ["$3"], + r4: reg = ["$4"], + r5: reg = ["$5"], + r6: reg = ["$6"], + r7: reg = ["$7"], // FIXME: Reserve $t0, $t1 if in mips16 mode. - t0: reg = ["$8", "$t0"], - t1: reg = ["$9", "$t1"], - t2: reg = ["$10", "$t2"], - t3: reg = ["$11", "$t3"], - t4: reg = ["$12", "$t4"], - t5: reg = ["$13", "$t5"], - t6: reg = ["$14", "$t6"], - t7: reg = ["$15", "$t7"], - s0: reg = ["$16", "$s0"], - s1: reg = ["$17", "$s1"], - s2: reg = ["$18", "$s2"], - s3: reg = ["$19", "$s3"], - s4: reg = ["$20", "$s4"], - s5: reg = ["$21", "$s5"], - s6: reg = ["$22", "$s6"], - s7: reg = ["$23", "$s7"], - t8: reg = ["$24", "$t8"], - t9: reg = ["$25", "$t9"], + r8: reg = ["$8"], + r9: reg = ["$9"], + r10: reg = ["$10"], + r11: reg = ["$11"], + r12: reg = ["$12"], + r13: reg = ["$13"], + r14: reg = ["$14"], + r15: reg = ["$15"], + r16: reg = ["$16"], + r17: reg = ["$17"], + r18: reg = ["$18"], + r19: reg = ["$19"], + r20: reg = ["$20"], + r21: reg = ["$21"], + r22: reg = ["$22"], + r23: reg = ["$23"], + r24: reg = ["$24"], + r25: reg = ["$25"], f0: freg = ["$f0"], f1: freg = ["$f1"], f2: freg = ["$f2"], @@ -101,21 +102,21 @@ def_regs! { f29: freg = ["$f29"], f30: freg = ["$f30"], f31: freg = ["$f31"], - #error = ["$0", "$zero"] => + #error = ["$0"] => "constant zero cannot be used as an operand for inline asm", - #error = ["$1", "$at"] => + #error = ["$1"] => "reserved for assembler (Assembler Temp)", - #error = ["$26", "$k0"] => + #error = ["$26"] => "OS-reserved register cannot be used as an operand for inline asm", - #error = ["$27", "$k1"] => + #error = ["$27"] => "OS-reserved register cannot be used as an operand for inline asm", - #error = ["$28", "$gp"] => + #error = ["$28"] => "the global pointer cannot be used as an operand for inline asm", - #error = ["$29", "$sp"] => + #error = ["$29"] => "the stack pointer cannot be used as an operand for inline asm", - #error = ["$30", "$s8", "$fp"] => + #error = ["$30"] => "the frame pointer cannot be used as an operand for inline asm", - #error = ["$31", "$ra"] => + #error = ["$31"] => "the return address register cannot be used as an operand for inline asm", } } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index e2f8e91fa95..0d691dc441e 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -176,6 +176,7 @@ pub enum InlineAsmArch { Nvptx64, Hexagon, Mips, + Mips64, } impl FromStr for InlineAsmArch { @@ -192,6 +193,7 @@ impl FromStr for InlineAsmArch { "nvptx64" => Ok(Self::Nvptx64), "hexagon" => Ok(Self::Hexagon), "mips" => Ok(Self::Mips), + "mips64" => Ok(Self::Mips64), _ => Err(()), } } @@ -259,7 +261,7 @@ impl InlineAsmReg { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?) } - InlineAsmArch::Mips => { + InlineAsmArch::Mips | InlineAsmArch::Mips64 => { Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?) } }) @@ -409,7 +411,9 @@ impl InlineAsmRegClass { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?) } - InlineAsmArch::Mips => Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?), + InlineAsmArch::Mips | InlineAsmArch::Mips64 => { + Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?) + } }) }) } @@ -565,7 +569,7 @@ pub fn allocatable_registers( hexagon::fill_reg_map(arch, has_feature, target, &mut map); map } - InlineAsmArch::Mips => { + InlineAsmArch::Mips | InlineAsmArch::Mips64 => { let mut map = mips::regclass_map(); mips::fill_reg_map(arch, has_feature, target, &mut map); map diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index b24518beae2..c15bd9a08fc 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { Target { llvm_target, target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(), arch: arch.to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs index ab20ec041ab..0019fc4492d 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "arm64-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs index 4619197fc69..276682c591d 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "arm64-apple-tvos".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs index beb2a0912e6..1f81a03c4a5 100644 --- a/compiler/rustc_target/src/spec/aarch64_fuchsia.rs +++ b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-fuchsia".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs index 519fd98d200..1ed4f0da79c 100644 --- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs index 09df41d3360..32fa2d69540 100644 --- a/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs index cecf3860fa5..f9d62519bd9 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-cloudabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs index 78e9f990de2..3d008290240 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-freebsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs index c0532925fb9..a7050cbee9e 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-hermit".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs index 67ee463c178..10255012e41 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_env: "gnu".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs index cb566c84ed7..f530163faf7 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_env: "musl".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs index d6990f7430f..dcb157d7aab 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-netbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs index fd45acb332a..6d3e72906d5 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs @@ -24,7 +24,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs index 666f417036e..784cd7eb3c9 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs @@ -24,7 +24,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-none".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs index 2b7dbc0ebdb..e03690e86b8 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-openbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs index 5f151473e0f..13adec9d4c4 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-redox".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs index 7dfcc1c065f..d6af5dd3628 100644 --- a/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs index fc2d192ef12..6fce200a96e 100644 --- a/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "aarch64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(), arch: "aarch64".to_string(), diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs index bb11ce8ef28..0824bc30358 100644 --- a/compiler/rustc_target/src/spec/android_base.rs +++ b/compiler/rustc_target/src/spec/android_base.rs @@ -9,6 +9,7 @@ pub fn opts() -> TargetOptions { .unwrap() .push("-Wl,--allow-multiple-definition".to_string()); base.is_like_android = true; + base.dwarf_version = Some(2); base.position_independent_executables = true; base.has_elf_tls = false; base.requires_uwtable = true; diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index e7b565ae9ca..2e3c835c0e5 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions { executables: true, target_family: Some("unix".to_string()), is_like_osx: true, + dwarf_version: Some(2), has_rpath: true, dll_prefix: "lib".to_string(), dll_suffix: ".dylib".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs index 7ea00800562..f9c69217460 100644 --- a/compiler/rustc_target/src/spec/arm_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "arm-linux-androideabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs index 0573cf5ba9d..96a444fc465 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "arm-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs index dbd68e366a1..534b98cc607 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "arm-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs index cd5c181ec61..e5fa3e3a1cb 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs @@ -13,7 +13,7 @@ pub fn target() -> Target { // support the "musleabi" value. llvm_target: "arm-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs index 2b99cd01e59..b631a0010a0 100644 --- a/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs @@ -13,7 +13,7 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "arm-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs index c414810dab2..86d0cd57af3 100644 --- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "armebv7r-unknown-none-eabi".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs index 608095db197..9ea44b3b25e 100644 --- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "armebv7r-unknown-none-eabihf".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs index 3ebf60f855e..be32731a869 100644 --- a/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv4t-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs index ff7d7e6c087..4ea4b650623 100644 --- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv5te-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs index da9855bbe55..a41a5409ac9 100644 --- a/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv5te-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs index 902dac30b51..68f6502133a 100644 --- a/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv6-unknown-freebsd-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs index 7f611defe90..23a20ca1c9f 100644 --- a/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "armv6-unknown-netbsdelf-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs index ac24e872a9a..24a47dd56a9 100644 --- a/compiler/rustc_target/src/spec/armv7_apple_ios.rs +++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs index ebaef615ac3..342959883cb 100644 --- a/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-none-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs index 5a1391ccedd..d4bb4e963fb 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-cloudabi-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs index 08d7d268148..c32e2d4376e 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-freebsd-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs index 02abd02f3b2..66d3b3e5d07 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs index d63c728fe4b..c1ef540a01d 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs index 93a004fa002..d4d26b14556 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs @@ -13,7 +13,7 @@ pub fn target() -> Target { // support the "musleabi" value. llvm_target: "armv7-unknown-linux-gnueabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs index 93a87ff44ef..88db04a74e2 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs index c3a2324130c..fe2471ab0d0 100644 --- a/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-netbsdelf-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs index 4d95a279218..9b8cefdfa9e 100644 --- a/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs @@ -5,7 +5,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs index dfd60601f4d..4199ac4569a 100644 --- a/compiler/rustc_target/src/spec/armv7a_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs @@ -35,7 +35,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs index 340d9788d23..99a06590097 100644 --- a/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs @@ -23,7 +23,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7a-none-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs index a3994e72490..f0e79072bc1 100644 --- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs +++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7r-unknown-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs index 3248679dc45..4c464d2b256 100644 --- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7r-unknown-none-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs index 54f1b1a2ac2..4c2d70ae34b 100644 --- a/compiler/rustc_target/src/spec/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7s-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p:32:32-Fi8-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs index 83a048b06ba..01445dc3898 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -9,7 +9,7 @@ pub fn target(target_cpu: String) -> Target { data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(), llvm_target: "avr-unknown-unknown".to_string(), target_endian: "little".to_string(), - target_pointer_width: "16".to_string(), + pointer_width: 16, linker_flavor: LinkerFlavor::Gcc, target_os: "unknown".to_string(), target_env: "".to_string(), diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs index c7062e1ca51..82dc5f54659 100644 --- a/compiler/rustc_target/src/spec/dragonfly_base.rs +++ b/compiler/rustc_target/src/spec/dragonfly_base.rs @@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions { pre_link_args: args, position_independent_executables: true, relro_level: RelroLevel::Full, + dwarf_version: Some(2), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs index d2a087ab62f..051325a8df6 100644 --- a/compiler/rustc_target/src/spec/freebsd_base.rs +++ b/compiler/rustc_target/src/spec/freebsd_base.rs @@ -26,6 +26,7 @@ pub fn opts() -> TargetOptions { eliminate_frame_pointer: false, // FIXME 43575 relro_level: RelroLevel::Full, abi_return_struct_as_int: true, + dwarf_version: Some(2), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs index 65b305aa84b..143b93dfeef 100644 --- a/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs @@ -20,7 +20,7 @@ pub fn target() -> Target { Target { llvm_target: "hexagon-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: concat!( "e-m:e-p:32:32:32-a:0-n16:32-i64:64:64-i32:32", diff --git a/compiler/rustc_target/src/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs index 4f6b8b25842..21421497965 100644 --- a/compiler/rustc_target/src/spec/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:128-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index 62a0e415094..9c7e7241b57 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { Target { llvm_target, target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:128-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs index 529e0d39290..d116ae62e0f 100644 --- a/compiler/rustc_target/src/spec/i686_linux_android.rs +++ b/compiler/rustc_target/src/spec/i686_linux_android.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs index 64a975ee1bc..84585bd515a 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs @@ -19,7 +19,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs index 2de1f07844e..db20b6094b7 100644 --- a/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs @@ -23,7 +23,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs index 6cd34f38c57..d9365d59e0e 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-cloudabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs index 691820a3010..ba379a40f50 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-freebsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs index cfc3a74104b..02754b39fa7 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-haiku".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs index 1e0efca8eed..b7ceaefef93 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs index 6e4259176cf..9240b56aeaf 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs @@ -25,7 +25,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs index 7305578ab6a..a4421924a7b 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-netbsdelf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs index f5b292685fa..fe5030f661b 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-openbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs index bb3b0b70744..676a8ca0acc 100644 --- a/compiler/rustc_target/src/spec/i686_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs @@ -79,7 +79,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs index 100e0706bc1..ec5a9cc68ce 100644 --- a/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs @@ -18,7 +18,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs index d4426a4eb9e..d960a130351 100644 --- a/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:32-n8:16:32-a:0:32-S32" diff --git a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs index 8320beefb27..0e5c7b6143e 100644 --- a/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "i686-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ f64:32:64-f80:32-n8:16:32-S128" diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs index f20d337931e..5cbd6bcd3d8 100644 --- a/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mips64-unknown-linux-gnuabi64".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs index edddcd616bf..3ca92dd1d04 100644 --- a/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64-unknown-linux-musl".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs index 031c5229f7e..4761be5b7ef 100644 --- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mips64el-unknown-linux-gnuabi64".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs index d76d0d3930b..d87170b6868 100644 --- a/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs +++ b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { // LLVM doesn't recognize "muslabi64" yet. llvm_target: "mips64el-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs index ebead1ce64f..e51cf3c59f6 100644 --- a/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs index 0042244569a..44d136ee7e9 100644 --- a/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-musl".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs index bdb9be4a027..7e168836dc7 100644 --- a/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mips-unknown-linux-uclibc".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs index 5d8ad510d60..9897b0093fc 100644 --- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs +++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-sony-psp".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs index ef585a4bc37..509f3e04ba7 100644 --- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs index 3552abd0968..0d3691dd5b9 100644 --- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs index b52ae5cc016..6d50d9ba81e 100644 --- a/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs +++ b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsel-unknown-linux-uclibc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs index 10ec589ef20..d6e71d2922f 100644 --- a/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa32r6-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs index 8157cac4170..67e97fd2f0f 100644 --- a/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa32r6el-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".to_string(), arch: "mips".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs index e5d565f653c..c3a7ae8b11f 100644 --- a/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa64r6-unknown-linux-gnuabi64".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs index 5f68c6484c0..467e05a00d4 100644 --- a/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs +++ b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "mipsisa64r6el-unknown-linux-gnuabi64".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128".to_string(), arch: "mips64".to_string(), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 0cb072f387f..1d3e61c4992 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -665,8 +665,8 @@ pub struct Target { pub llvm_target: String, /// String to use as the `target_endian` `cfg` variable. pub target_endian: String, - /// String to use as the `target_pointer_width` `cfg` variable. - pub target_pointer_width: String, + /// Number of bits in a pointer. Influences the `target_pointer_width` `cfg` variable. + pub pointer_width: u32, /// Width of c_int type pub target_c_int_width: String, /// OS name to use for conditional compilation. @@ -816,6 +816,9 @@ pub struct TargetOptions { pub is_like_emscripten: bool, /// Whether the target toolchain is like Fuchsia's. pub is_like_fuchsia: bool, + /// Version of DWARF to use if not using the default. + /// Useful because some platforms (osx, bsd) only want up to DWARF2. + pub dwarf_version: Option<u32>, /// Whether the linker support GNU-like arguments such as -O. Defaults to false. pub linker_is_gnu: bool, /// The MinGW toolchain has a known issue that prevents it from correctly @@ -1012,6 +1015,7 @@ impl Default for TargetOptions { is_like_emscripten: false, is_like_msvc: false, is_like_fuchsia: false, + dwarf_version: None, linker_is_gnu: false, allows_weak_linkage: true, has_rpath: false, @@ -1107,7 +1111,7 @@ impl Target { /// Maximum integer size in bits that this target can perform atomic /// operations on. pub fn max_atomic_width(&self) -> u64 { - self.options.max_atomic_width.unwrap_or_else(|| self.target_pointer_width.parse().unwrap()) + self.options.max_atomic_width.unwrap_or_else(|| self.pointer_width.into()) } pub fn is_abi_supported(&self, abi: Abi) -> bool { @@ -1140,7 +1144,9 @@ impl Target { let mut base = Target { llvm_target: get_req_field("llvm-target")?, target_endian: get_req_field("target-endian")?, - target_pointer_width: get_req_field("target-pointer-width")?, + pointer_width: get_req_field("target-pointer-width")? + .parse::<u32>() + .map_err(|_| "target-pointer-width must be an integer".to_string())?, target_c_int_width: get_req_field("target-c-int-width")?, data_layout: get_req_field("data-layout")?, arch: get_req_field("arch")?, @@ -1165,6 +1171,15 @@ impl Target { base.options.$key_name = s; } } ); + ($key_name:ident, Option<u32>) => ( { + let name = (stringify!($key_name)).replace("_", "-"); + if let Some(s) = obj.find(&name).and_then(Json::as_u64) { + if s < 1 || s > 5 { + return Err("Not a valid DWARF version number".to_string()); + } + base.options.$key_name = Some(s as u32); + } + } ); ($key_name:ident, Option<u64>) => ( { let name = (stringify!($key_name)).replace("_", "-"); if let Some(s) = obj.find(&name).and_then(Json::as_u64) { @@ -1417,6 +1432,7 @@ impl Target { key!(is_like_emscripten, bool); key!(is_like_android, bool); key!(is_like_fuchsia, bool); + key!(dwarf_version, Option<u32>); key!(linker_is_gnu, bool); key!(allows_weak_linkage, bool); key!(has_rpath, bool); @@ -1603,7 +1619,7 @@ impl ToJson for Target { target_val!(llvm_target); target_val!(target_endian); - target_val!(target_pointer_width); + d.insert("target-pointer-width".to_string(), self.pointer_width.to_string().to_json()); target_val!(target_c_int_width); target_val!(arch); target_val!(target_os, "os"); @@ -1654,6 +1670,7 @@ impl ToJson for Target { target_option_val!(is_like_emscripten); target_option_val!(is_like_android); target_option_val!(is_like_fuchsia); + target_option_val!(dwarf_version); target_option_val!(linker_is_gnu); target_option_val!(allows_weak_linkage); target_option_val!(has_rpath); diff --git a/compiler/rustc_target/src/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs index 9274d750c7c..5bb8109ce26 100644 --- a/compiler/rustc_target/src/spec/msp430_none_elf.rs +++ b/compiler/rustc_target/src/spec/msp430_none_elf.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "msp430-none-elf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "16".to_string(), + pointer_width: 16, target_c_int_width: "16".to_string(), data_layout: "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16".to_string(), arch: "msp430".to_string(), diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs index 988346af2d7..d7baf81fce3 100644 --- a/compiler/rustc_target/src/spec/netbsd_base.rs +++ b/compiler/rustc_target/src/spec/netbsd_base.rs @@ -24,6 +24,7 @@ pub fn opts() -> TargetOptions { position_independent_executables: true, relro_level: RelroLevel::Full, use_ctors_section: true, + dwarf_version: Some(2), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs index e44534a288d..86360c181d1 100644 --- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::PtxLinker, target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), options: TargetOptions { diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs index cadd14df693..92a382e826b 100644 --- a/compiler/rustc_target/src/spec/openbsd_base.rs +++ b/compiler/rustc_target/src/spec/openbsd_base.rs @@ -26,6 +26,7 @@ pub fn opts() -> TargetOptions { position_independent_executables: true, eliminate_frame_pointer: false, // FIXME 43575 relro_level: RelroLevel::Full, + dwarf_version: Some(2), ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs index ab889387e2b..563ff96a403 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-freebsd".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs index 84a19e8a047..7d37670e5b0 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs @@ -13,7 +13,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs index c320d10e6c1..e108d75f337 100644 --- a/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-musl".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs index 257a0932080..9784c637c7e 100644 --- a/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs index 5d501f840b6..46d847f6e5f 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs index 847e8abf299..e04ee013701 100644 --- a/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc64le-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-i64:64-n32:64".to_string(), arch: "powerpc64".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs index 5f55a233fc4..80fc63e78e4 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs index b3c3a2fe242..612d2967ee0 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnuspe".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs index 804f223ba6e..fd89262e464 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-musl".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs index 5be35dbdc89..d33258d1859 100644 --- a/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-netbsd".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs index 44338c066e6..6a12f4c59f6 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs index e2dc7858d2c..5fee61fa0bd 100644 --- a/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs +++ b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "powerpc-unknown-linux-gnuspe".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-n32".to_string(), arch: "powerpc".to_string(), diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs index bce690662b8..415d7c5607d 100644 --- a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "riscv32-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_env: "gnu".to_string(), data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), diff --git a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs index 83e27c4d838..022768f6ab8 100644 --- a/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), llvm_target: "riscv32".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs index e2154f58494..13f0d42d6fd 100644 --- a/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), llvm_target: "riscv32".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs index 845a80a06c7..86189c27bbd 100644 --- a/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), llvm_target: "riscv32".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs index 2cd3b952618..808d7159f82 100644 --- a/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs @@ -4,7 +4,7 @@ pub fn target() -> Target { Target { llvm_target: "riscv64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_env: "gnu".to_string(), data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(), diff --git a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs index 1f857159f0c..0211bc02d2d 100644 --- a/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(), llvm_target: "riscv64".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs index c407fd9557d..1050ce5ba74 100644 --- a/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs +++ b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".to_string(), llvm_target: "riscv64".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs index ed1c96f1d7b..653b83646ce 100644 --- a/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "s390x-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64".to_string(), arch: "s390x".to_string(), diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs index 8b540a717ce..e50c114fcfa 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), arch: "sparc64".to_string(), diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs index cfdc43547ff..6d8e433949b 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-netbsd".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), arch: "sparc64".to_string(), diff --git a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs index 6f2eaeee32a..45700e14c53 100644 --- a/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "sparc64-unknown-openbsd".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), arch: "sparc64".to_string(), diff --git a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs index ea02db7e5bb..fc400dd3446 100644 --- a/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "sparc-unknown-linux-gnu".to_string(), target_endian: "big".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "E-m:e-p:32:32-i64:64-f128:64-n32-S64".to_string(), arch: "sparc".to_string(), diff --git a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs index 747f70e65c5..0878e7fd21e 100644 --- a/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "sparcv9-sun-solaris".to_string(), target_endian: "big".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "E-m:e-i64:64-n32:64-S128".to_string(), // Use "sparc64" instead of "sparcv9" here, since the former is already diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs index d1fd0fea604..d5ce62d8c1c 100644 --- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv4t-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "none".to_string(), target_env: "".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs index bd1367ddb42..407fa6116c5 100644 --- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv6m-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs index 01a3598572d..d34f42cdc61 100644 --- a/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs @@ -24,7 +24,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7a-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs index af4741c77ab..143a9a48a4a 100644 --- a/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7a-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs index 10e1050fbf5..e0b00460e08 100644 --- a/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs @@ -15,7 +15,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7em-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs index 17a5b70bc09..eecd75e4614 100644 --- a/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7em-none-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs index c21cb5d03d4..a02100ee199 100644 --- a/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv7m-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs index 8c4750d7731..35e7d480f3f 100644 --- a/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-none-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs index 85bdc16727b..946b0db4c22 100644 --- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs index b97b5270d42..91945f9dcdc 100644 --- a/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { // doesn't support the "musleabihf" value. llvm_target: "armv7-unknown-linux-gnueabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs index 9eb33f5ef66..383346400b5 100644 --- a/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.base-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs index 55b8b545e79..3d0fb664cf6 100644 --- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.main-none-eabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs index f17d48e8523..82368cb59b2 100644 --- a/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs @@ -7,7 +7,7 @@ pub fn target() -> Target { Target { llvm_target: "thumbv8m.main-none-eabihf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(), arch: "arm".to_string(), diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index 4f99967f21b..aea06412aa2 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -31,7 +31,7 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-emscripten".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "emscripten".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs index f0b6979ce11..19609b0d496 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs @@ -33,7 +33,7 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-unknown-unknown".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "unknown".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs index f8fdbf44b19..26e0722fcf0 100644 --- a/compiler/rustc_target/src/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -107,7 +107,7 @@ pub fn target() -> Target { Target { llvm_target: "wasm32-wasi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), target_os: "wasi".to_string(), target_env: String::new(), diff --git a/compiler/rustc_target/src/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs index 0234ff55f01..98e42f6c37c 100644 --- a/compiler/rustc_target/src/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -11,6 +11,10 @@ pub fn opts() -> TargetOptions { "-fno-use-linker-plugin".to_string(), // Always enable DEP (NX bit) when it is available "-Wl,--nxcompat".to_string(), + // Enable ASLR + "-Wl,--dynamicbase".to_string(), + // ASLR will rebase it anyway so leaving that option enabled only leads to confusion + "-Wl,--disable-auto-image-base".to_string(), ], ); diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index 45e8ddd6137..2b39fec594a 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -21,7 +21,7 @@ pub fn target() -> Target { Target { llvm_target, target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs index b4590f7aed2..685e046b64b 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-apple-ios".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs index 85cc4e6db6f..ff7331560ed 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-apple-ios13.0-macabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index db466400562..7c0a819f5dd 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -6,7 +6,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-apple-tvos".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:o-i64:64-f80:128-n8:16:32:64-S128".to_string(), arch: "x86_64".to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs index cc27d88bff1..8f1627d4a29 100644 --- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs @@ -77,7 +77,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-elf".into(), target_endian: "little".into(), - target_pointer_width: "64".into(), + pointer_width: 64, target_c_int_width: "32".into(), target_os: "unknown".into(), target_env: "sgx".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs index 887b3b67edd..71add0a6c0a 100644 --- a/compiler/rustc_target/src/spec/x86_64_fuchsia.rs +++ b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-fuchsia".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index 44c869d1e30..aa5e48cee07 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-linux-android".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs index b9507ad9c8e..243167558be 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs @@ -17,7 +17,7 @@ pub fn target() -> Target { // FIXME: Some dispute, the linux-on-clang folks think this should use "Linux" llvm_target: "x86_64-elf".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs index e93755d1aa4..3b2edc91bc2 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs @@ -3,7 +3,10 @@ use crate::spec::{LinkerFlavor, LldFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_gnu_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + gcc_pre_link_args.push("-m64".to_string()); + // Use high-entropy 64 bit address space for ASLR + gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string()); base.pre_link_args .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]); base.max_atomic_width = Some(64); @@ -12,7 +15,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs index ffb0eb43beb..f21b059551d 100644 --- a/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs index 3d97f4315ec..2e009d7abbf 100644 --- a/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs @@ -16,7 +16,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-rumprun-netbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs index 5c6be285360..aef06157cdd 100644 --- a/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs +++ b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-solaris".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs index c002671552f..bdaab883d90 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-cloudabi".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs index 1390926ed3f..13a62d5081c 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-dragonfly".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index 424f0343ec9..145983022e8 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-freebsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs index 2f9be167b9b..d88812e4248 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-haiku".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs index 0da92f035a5..a5002091d07 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-hermit".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs index ea955e758bb..91d7b0eaefc 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs @@ -12,7 +12,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-hermit".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs index 482748f5b3d..e49f009be0f 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { // so we still pass Solaris to it llvm_target: "x86_64-pc-solaris".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs index 65e080d3066..fc5b1ba60ec 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs @@ -8,7 +8,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-l4re-uclibc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index 66df76cad69..9d9f99c9b59 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs index 81dae46b8a3..e4a0d913bab 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs @@ -14,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnux32".to_string(), target_endian: "little".to_string(), - target_pointer_width: "32".to_string(), + pointer_width: 32, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-\ i64:64-f80:128-n8:16:32:64-S128" diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index e513df790be..a7d3324b2c7 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-musl".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index 9c984f169a6..a8106c0c770 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-netbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index d9110c882c1..5afe73ea713 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-openbsd".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs index 42af9c799bd..e21148887d9 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs @@ -10,7 +10,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-redox".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs index 17d75a96713..894bd334169 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs @@ -31,7 +31,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-windows".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs index b288271406c..a4fa0d03546 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs @@ -3,7 +3,10 @@ use crate::spec::{LinkerFlavor, LldFlavor, Target}; pub fn target() -> Target { let mut base = super::windows_uwp_gnu_base::opts(); base.cpu = "x86-64".to_string(); - base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap().push("-m64".to_string()); + let gcc_pre_link_args = base.pre_link_args.get_mut(&LinkerFlavor::Gcc).unwrap(); + gcc_pre_link_args.push("-m64".to_string()); + // Use high-entropy 64 bit address space for ASLR + gcc_pre_link_args.push("-Wl,--high-entropy-va".to_string()); base.pre_link_args .insert(LinkerFlavor::Lld(LldFlavor::Ld), vec!["-m".to_string(), "i386pep".to_string()]); base.max_atomic_width = Some(64); @@ -11,7 +14,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs index 41beab91536..aaf85bbce81 100644 --- a/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs +++ b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs @@ -9,7 +9,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-pc-windows-msvc".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs index 96927660a3c..5edf7e7af51 100644 --- a/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs +++ b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs @@ -11,7 +11,7 @@ pub fn target() -> Target { Target { llvm_target: "x86_64-unknown-linux-gnu".to_string(), target_endian: "little".to_string(), - target_pointer_width: "64".to_string(), + pointer_width: 64, target_c_int_width: "32".to_string(), data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" .to_string(), diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index 610c6fd7e35..ecaafee77e2 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -717,6 +717,8 @@ where ty::Closure(_, ref substs) => { // Skip lifetime parameters of the enclosing item(s) + substs.as_closure().tupled_upvars_ty().visit_with(self); + for upvar_ty in substs.as_closure().upvar_tys() { upvar_ty.visit_with(self); } @@ -728,6 +730,8 @@ where // Skip lifetime parameters of the enclosing item(s) // Also skip the witness type, because that has no free regions. + substs.as_generator().tupled_upvars_ty().visit_with(self); + for upvar_ty in substs.as_generator().upvar_tys() { upvar_ty.visit_with(self); } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 3828cf4d302..1e1eb16faf4 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -147,11 +147,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>( if concrete.is_ok() && substs.has_param_types_or_consts() { match infcx.tcx.def_kind(def.did) { DefKind::AnonConst => { - let mir_body = if let Some(def) = def.as_const_arg() { - infcx.tcx.optimized_mir_of_const_arg(def) - } else { - infcx.tcx.optimized_mir(def.did) - }; + let mir_body = infcx.tcx.optimized_mir_opt_const_arg(def); if mir_body.is_polymorphic { future_compat_lint(); @@ -212,13 +208,7 @@ impl AbstractConst<'tcx> { def: ty::WithOptConstParam<DefId>, substs: SubstsRef<'tcx>, ) -> Result<Option<AbstractConst<'tcx>>, ErrorReported> { - let inner = match (def.did.as_local(), def.const_param_did) { - (Some(did), Some(param_did)) => { - tcx.mir_abstract_const_of_const_arg((did, param_did))? - } - _ => tcx.mir_abstract_const(def.did)?, - }; - + let inner = tcx.mir_abstract_const_opt_const_arg(def)?; Ok(inner.map(|inner| AbstractConst { inner, substs })) } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index cb3de57cfed..05e3ed34351 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -1384,17 +1384,11 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: &ty::PolyTraitRef<'tcx>, ) { let get_trait_impl = |trait_def_id| { - let mut trait_impl = None; - self.tcx.for_each_relevant_impl( + self.tcx.find_map_relevant_impl( trait_def_id, trait_ref.skip_binder().self_ty(), - |impl_def_id| { - if trait_impl.is_none() { - trait_impl = Some(impl_def_id); - } - }, - ); - trait_impl + |impl_def_id| Some(impl_def_id), + ) }; let required_trait_path = self.tcx.def_path_str(trait_ref.def_id()); let all_traits = self.tcx.all_traits(LOCAL_CRATE); diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 967374ffdc2..efa9bd633ba 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -22,6 +22,7 @@ use rustc_middle::ty::{ use rustc_middle::ty::{TypeAndMut, TypeckResults}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; +use rustc_target::spec::abi; use std::fmt; use super::InferCtxtPrivExt; @@ -1157,15 +1158,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, - ::rustc_target::spec::abi::Abi::Rust, + abi::Abi::Rust, ) } else { tcx.mk_fn_sig( - ::std::iter::once(inputs), + std::iter::once(inputs), tcx.mk_ty_infer(ty::TyVar(ty::TyVid { index: 0 })), false, hir::Unsafety::Normal, - ::rustc_target::spec::abi::Abi::Rust, + abi::Abi::Rust, ) }; ty::Binder::bind(sig).to_string() @@ -1307,6 +1308,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let mut generator = None; let mut outer_generator = None; let mut next_code = Some(&obligation.cause.code); + + let mut seen_upvar_tys_infer_tuple = false; + while let Some(code) = next_code { debug!("maybe_note_obligation_cause_for_async_await: code={:?}", code); match code { @@ -1327,6 +1331,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { outer_generator = Some(did); } ty::GeneratorWitness(..) => {} + ty::Tuple(_) if !seen_upvar_tys_infer_tuple => { + // By introducing a tuple of upvar types into the chain of obligations + // of a generator, the first non-generator item is now the tuple itself, + // we shall ignore this. + + seen_upvar_tys_infer_tuple = true; + } _ if generator.is_none() => { trait_ref = Some(derived_obligation.parent_trait_ref.skip_binder()); target_ty = Some(ty); @@ -1912,7 +1923,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - err.note(&format!("required because it appears within the type `{}`", ty)); + // If the obligation for a tuple is set directly by a Generator or Closure, + // then the tuple must be the one containing capture types. + let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) { + false + } else { + if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = + *data.parent_code + { + let parent_trait_ref = + self.resolve_vars_if_possible(&data.parent_trait_ref); + let ty = parent_trait_ref.skip_binder().self_ty(); + matches!(ty.kind(), ty::Generator(..)) + || matches!(ty.kind(), ty::Closure(..)) + } else { + false + } + }; + + // Don't print the tuple of capture types + if !is_upvar_tys_infer_tuple { + err.note(&format!("required because it appears within the type `{}`", ty)); + } + obligated_types.push(ty); let parent_predicate = parent_trait_ref.without_const().to_predicate(tcx); diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 27751eb554d..97dd180b27b 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -120,7 +120,8 @@ impl<'a, 'tcx> FulfillmentContext<'tcx> { &mut self, selcx: &mut SelectionContext<'a, 'tcx>, ) -> Result<(), Vec<FulfillmentError<'tcx>>> { - debug!("select(obligation-forest-size={})", self.predicates.len()); + let span = debug_span!("select", obligation_forest_size = ?self.predicates.len()); + let _enter = span.enter(); let mut errors = Vec::new(); @@ -173,7 +174,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, ) -> Ty<'tcx> { - debug!("normalize_projection_type(projection_ty={:?})", projection_ty); + debug!(?projection_ty, "normalize_projection_type"); debug_assert!(!projection_ty.has_escaping_bound_vars()); @@ -191,7 +192,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { ); self.register_predicate_obligations(infcx, obligations); - debug!("normalize_projection_type: result={:?}", normalized_ty); + debug!(?normalized_ty); normalized_ty } @@ -205,7 +206,7 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { // debug output much nicer to read and so on. let obligation = infcx.resolve_vars_if_possible(&obligation); - debug!("register_predicate_obligation(obligation={:?})", obligation); + debug!(?obligation, "register_predicate_obligation"); assert!(!infcx.is_in_snapshot() || self.usable_in_snapshot); @@ -342,7 +343,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { self.selcx.infcx().resolve_vars_if_possible(&obligation.predicate); } - debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); + debug!(?obligation, ?obligation.cause, "process_obligation"); let infcx = self.selcx.infcx(); @@ -509,7 +510,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } ty::PredicateAtom::ConstEquate(c1, c2) => { - debug!("equating consts: c1={:?} c2={:?}", c1, c2); + debug!(?c1, ?c2, "equating consts"); if self.selcx.tcx().features().const_evaluatable_checked { // FIXME: we probably should only try to unify abstract constants // if the constants depend on generic parameters. @@ -601,6 +602,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { } } + #[instrument(level = "debug", skip(self, obligation, stalled_on))] fn process_trait_obligation( &mut self, obligation: &PredicateObligation<'tcx>, @@ -613,8 +615,8 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { // FIXME: consider caching errors too. if infcx.predicate_must_hold_considering_regions(obligation) { debug!( - "selecting trait `{:?}` at depth {} evaluated to holds", - obligation.predicate, obligation.recursion_depth + "selecting trait at depth {} evaluated to holds", + obligation.recursion_depth ); return ProcessResult::Changed(vec![]); } @@ -622,17 +624,11 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { match self.selcx.select(&trait_obligation) { Ok(Some(impl_source)) => { - debug!( - "selecting trait `{:?}` at depth {} yielded Ok(Some)", - trait_obligation.predicate, obligation.recursion_depth - ); + debug!("selecting trait at depth {} yielded Ok(Some)", obligation.recursion_depth); ProcessResult::Changed(mk_pending(impl_source.nested_obligations())) } Ok(None) => { - debug!( - "selecting trait `{:?}` at depth {} yielded Ok(None)", - trait_obligation.predicate, obligation.recursion_depth - ); + debug!("selecting trait at depth {} yielded Ok(None)", obligation.recursion_depth); // This is a bit subtle: for the most part, the // only reason we can fail to make progress on @@ -652,10 +648,7 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ProcessResult::Unchanged } Err(selection_err) => { - info!( - "selecting trait `{:?}` at depth {} yielded Err", - trait_obligation.predicate, obligation.recursion_depth - ); + info!("selecting trait at depth {} yielded Err", obligation.recursion_depth); ProcessResult::Error(CodeSelectionError(selection_err)) } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index de42aa0e6b7..8dbf7ec51c6 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -157,6 +157,7 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> { /// the given obligations. If the projection cannot be normalized because /// the required trait bound doesn't hold this returned with `obligations` /// being a predicate that cannot be proven. +#[instrument(level = "debug", skip(selcx))] pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &PolyProjectionObligation<'tcx>, @@ -164,8 +165,6 @@ pub(super) fn poly_project_and_unify_type<'cx, 'tcx>( Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, MismatchedProjectionTypes<'tcx>, > { - debug!("poly_project_and_unify_type(obligation={:?})", obligation); - let infcx = selcx.infcx(); infcx.commit_if_ok(|_snapshot| { let placeholder_predicate = @@ -191,7 +190,7 @@ fn project_and_unify_type<'cx, 'tcx>( Result<Option<Vec<PredicateObligation<'tcx>>>, InProgress>, MismatchedProjectionTypes<'tcx>, > { - debug!("project_and_unify_type(obligation={:?})", obligation); + debug!(?obligation, "project_and_unify_type"); let mut obligations = vec![]; let normalized_ty = match opt_normalize_projection_type( @@ -207,10 +206,7 @@ fn project_and_unify_type<'cx, 'tcx>( Err(InProgress) => return Ok(Err(InProgress)), }; - debug!( - "project_and_unify_type: normalized_ty={:?} obligations={:?}", - normalized_ty, obligations - ); + debug!(?normalized_ty, ?obligations, "project_and_unify_type result"); let infcx = selcx.infcx(); match infcx @@ -275,6 +271,7 @@ where Normalized { value, obligations } } +#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -286,16 +283,10 @@ pub fn normalize_with_depth_to<'a, 'b, 'tcx, T>( where T: TypeFoldable<'tcx>, { - debug!("normalize_with_depth(depth={}, value={:?})", depth, value); let mut normalizer = AssocTypeNormalizer::new(selcx, param_env, cause, depth, obligations); let result = ensure_sufficient_stack(|| normalizer.fold(value)); - debug!( - "normalize_with_depth: depth={} result={:?} with {} obligations", - depth, - result, - normalizer.obligations.len() - ); - debug!("normalize_with_depth: depth={} obligations={:?}", depth, normalizer.obligations); + debug!(?result, obligations.len = normalizer.obligations.len()); + debug!(?normalizer.obligations,); result } @@ -396,12 +387,11 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { &mut self.obligations, ); debug!( - "AssocTypeNormalizer: depth={} normalized {:?} to {:?}, \ - now with {} obligations", - self.depth, - ty, - normalized_ty, - self.obligations.len() + ?self.depth, + ?ty, + ?normalized_ty, + obligations.len = ?self.obligations.len(), + "AssocTypeNormalizer: normalized type" ); normalized_ty } @@ -473,6 +463,7 @@ pub fn normalize_projection_type<'a, 'b, 'tcx>( /// often immediately appended to another obligations vector. So now this /// function takes an obligations vector and appends to it directly, which is /// slightly uglier but avoids the need for an extra short-lived allocation. +#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))] fn opt_normalize_projection_type<'a, 'b, 'tcx>( selcx: &'a mut SelectionContext<'b, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -486,13 +477,6 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( let projection_ty = infcx.resolve_vars_if_possible(&projection_ty); let cache_key = ProjectionCacheKey::new(projection_ty); - debug!( - "opt_normalize_projection_type(\ - projection_ty={:?}, \ - depth={})", - projection_ty, depth - ); - // FIXME(#20304) For now, I am caching here, which is good, but it // means we don't capture the type variables that are created in // the case of ambiguity. Which means we may create a large stream @@ -508,10 +492,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // If we found ambiguity the last time, that means we will continue // to do so until some type in the key changes (and we know it // hasn't, because we just fully resolved it). - debug!( - "opt_normalize_projection_type: \ - found cache entry: ambiguous" - ); + debug!("found cache entry: ambiguous"); return Ok(None); } Err(ProjectionCacheEntry::InProgress) => { @@ -529,10 +510,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // with `A::B`, which can trigger a recursive // normalization. - debug!( - "opt_normalize_projection_type: \ - found cache entry: in-progress" - ); + debug!("found cache entry: in-progress"); return Err(InProgress); } @@ -548,11 +526,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // discarded as duplicated). But when doing trait // evaluation this is not the case, and dropping the trait // evaluations can causes ICEs (e.g., #43132). - debug!( - "opt_normalize_projection_type: \ - found normalized ty `{:?}`", - ty - ); + debug!(?ty, "found normalized ty"); // Once we have inferred everything we need to know, we // can ignore the `obligations` from that point on. @@ -565,10 +539,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( return Ok(Some(ty.value)); } Err(ProjectionCacheEntry::Error) => { - debug!( - "opt_normalize_projection_type: \ - found error" - ); + debug!("opt_normalize_projection_type: found error"); let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); obligations.extend(result.obligations); return Ok(Some(result.value)); @@ -586,13 +557,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // an impl, where-clause etc) and hence we must // re-normalize it - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} \ - depth={} \ - projected_obligations={:?}", - projected_ty, depth, projected_obligations - ); + debug!(?projected_ty, ?depth, ?projected_obligations); let result = if projected_ty.has_projections() { let mut normalizer = AssocTypeNormalizer::new( @@ -604,11 +569,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( ); let normalized_ty = normalizer.fold(&projected_ty); - debug!( - "opt_normalize_projection_type: \ - normalized_ty={:?} depth={}", - normalized_ty, depth - ); + debug!(?normalized_ty, ?depth); Normalized { value: normalized_ty, obligations: projected_obligations } } else { @@ -621,21 +582,14 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( Ok(Some(result.value)) } Ok(ProjectedTy::NoProgress(projected_ty)) => { - debug!( - "opt_normalize_projection_type: \ - projected_ty={:?} no progress", - projected_ty - ); + debug!(?projected_ty, "opt_normalize_projection_type: no progress"); let result = Normalized { value: projected_ty, obligations: vec![] }; infcx.inner.borrow_mut().projection_cache().insert_ty(cache_key, result.clone()); // No need to extend `obligations`. Ok(Some(result.value)) } Err(ProjectionTyError::TooManyCandidates) => { - debug!( - "opt_normalize_projection_type: \ - too many candidates" - ); + debug!("opt_normalize_projection_type: too many candidates"); infcx.inner.borrow_mut().projection_cache().ambiguous(cache_key); Ok(None) } @@ -755,15 +709,12 @@ impl<'tcx> Progress<'tcx> { fn with_addl_obligations(mut self, mut obligations: Vec<PredicateObligation<'tcx>>) -> Self { debug!( - "with_addl_obligations: self.obligations.len={} obligations.len={}", - self.obligations.len(), - obligations.len() + self.obligations.len = ?self.obligations.len(), + obligations.len = obligations.len(), + "with_addl_obligations" ); - debug!( - "with_addl_obligations: self.obligations={:?} obligations={:?}", - self.obligations, obligations - ); + debug!(?self.obligations, ?obligations, "with_addl_obligations"); self.obligations.append(&mut obligations); self @@ -778,7 +729,7 @@ fn project_type<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, ) -> Result<ProjectedTy<'tcx>, ProjectionTyError<'tcx>> { - debug!("project(obligation={:?})", obligation); + debug!(?obligation, "project_type"); if !selcx.tcx().sess.recursion_limit().value_within_limit(obligation.recursion_depth) { debug!("project: overflow!"); @@ -787,7 +738,7 @@ fn project_type<'cx, 'tcx>( let obligation_trait_ref = &obligation.predicate.trait_ref(selcx.tcx()); - debug!("project: obligation_trait_ref={:?}", obligation_trait_ref); + debug!(?obligation_trait_ref); if obligation_trait_ref.references_error() { return Ok(ProjectedTy::Progress(Progress::error(selcx.tcx()))); @@ -951,10 +902,11 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( env_predicates: impl Iterator<Item = ty::Predicate<'tcx>>, potentially_unnormalized_candidates: bool, ) { - debug!("assemble_candidates_from_predicates(obligation={:?})", obligation); + debug!(?obligation, "assemble_candidates_from_predicates"); + let infcx = selcx.infcx(); for predicate in env_predicates { - debug!("assemble_candidates_from_predicates: predicate={:?}", predicate); + debug!(?predicate); if let ty::PredicateAtom::Projection(data) = predicate.skip_binders() { let data = ty::Binder::bind(data); let same_def_id = data.projection_def_id() == obligation.predicate.item_def_id; @@ -969,11 +921,7 @@ fn assemble_candidates_from_predicates<'cx, 'tcx>( ) }); - debug!( - "assemble_candidates_from_predicates: candidate={:?} \ - is_match={} same_def_id={}", - data, is_match, same_def_id - ); + debug!(?data, ?is_match, ?same_def_id); if is_match { candidate_set.push_candidate(ctor(data)); @@ -997,6 +945,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( obligation_trait_ref: &ty::TraitRef<'tcx>, candidate_set: &mut ProjectionTyCandidateSet<'tcx>, ) { + debug!("assemble_candidates_from_impls"); + // If we are resolving `<T as TraitRef<...>>::Item == Type`, // start out by selecting the predicate `T as TraitRef<...>`: let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref(); @@ -1009,7 +959,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( return Err(()); } Err(e) => { - debug!("assemble_candidates_from_impls: selection error {:?}", e); + debug!(error = ?e, "selection error"); candidate_set.mark_error(e); return Err(()); } @@ -1020,7 +970,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | super::ImplSource::Generator(_) | super::ImplSource::FnPointer(_) | super::ImplSource::TraitAlias(_) => { - debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source); + debug!(?impl_source); true } super::ImplSource::UserDefined(impl_data) => { @@ -1066,10 +1016,9 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( !poly_trait_ref.still_further_specializable() } else { debug!( - "assemble_candidates_from_impls: not eligible due to default: \ - assoc_ty={} predicate={}", - selcx.tcx().def_path_str(node_item.item.def_id), - obligation.predicate, + assoc_ty = ?selcx.tcx().def_path_str(node_item.item.def_id), + ?obligation.predicate, + "assemble_candidates_from_impls: not eligible due to default", ); false } @@ -1176,8 +1125,7 @@ fn confirm_candidate<'cx, 'tcx>( obligation: &ProjectionTyObligation<'tcx>, candidate: ProjectionTyCandidate<'tcx>, ) -> Progress<'tcx> { - debug!("confirm_candidate(candidate={:?}, obligation={:?})", candidate, obligation); - + debug!(?obligation, ?candidate, "confirm_candidate"); let mut progress = match candidate { ProjectionTyCandidate::ParamEnv(poly_projection) | ProjectionTyCandidate::Object(poly_projection) => { @@ -1220,9 +1168,8 @@ fn confirm_select_candidate<'cx, 'tcx>( | super::ImplSource::AutoImpl(..) | super::ImplSource::Param(..) | super::ImplSource::Builtin(..) - | super::ImplSource::TraitAlias(..) => - // we don't create Select candidates with this kind of resolution - { + | super::ImplSource::TraitAlias(..) => { + // we don't create Select candidates with this kind of resolution span_bug!( obligation.cause.span, "Cannot project an associated type from `{:?}`", @@ -1246,10 +1193,7 @@ fn confirm_generator_candidate<'cx, 'tcx>( &gen_sig, ); - debug!( - "confirm_generator_candidate: obligation={:?},gen_sig={:?},obligations={:?}", - obligation, gen_sig, obligations - ); + debug!(?obligation, ?gen_sig, ?obligations, "confirm_generator_candidate"); let tcx = selcx.tcx(); @@ -1339,10 +1283,7 @@ fn confirm_closure_candidate<'cx, 'tcx>( &closure_sig, ); - debug!( - "confirm_closure_candidate: obligation={:?},closure_sig={:?},obligations={:?}", - obligation, closure_sig, obligations - ); + debug!(?obligation, ?closure_sig, ?obligations, "confirm_closure_candidate"); confirm_callable_candidate(selcx, obligation, closure_sig, util::TupleArgumentsFlag::No) .with_addl_obligations(impl_source.nested) @@ -1357,7 +1298,7 @@ fn confirm_callable_candidate<'cx, 'tcx>( ) -> Progress<'tcx> { let tcx = selcx.tcx(); - debug!("confirm_callable_candidate({:?},{:?})", obligation, fn_sig); + debug!(?obligation, ?fn_sig, "confirm_callable_candidate"); let fn_once_def_id = tcx.require_lang_item(LangItem::FnOnce, None); let fn_once_output_def_id = tcx.require_lang_item(LangItem::FnOnceOutput, None); diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index 424b3bd67ff..8212823a6db 100644 --- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -110,7 +110,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { // check if *any* of those are trivial. ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), ty::Closure(_, ref substs) => { - substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t)) + trivial_dropck_outlives(tcx, substs.as_closure().tupled_upvars_ty()) } ty::Adt(def, _) => { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index bdbf45f78a2..d748fc8235e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -44,7 +44,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { { debug!( "normalize::<{}>(value={:?}, param_env={:?})", - ::std::any::type_name::<T>(), + std::any::type_name::<T>(), value, self.param_env, ); @@ -65,13 +65,13 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { let result = value.fold_with(&mut normalizer); debug!( "normalize::<{}>: result={:?} with {} obligations", - ::std::any::type_name::<T>(), + std::any::type_name::<T>(), result, normalizer.obligations.len(), ); debug!( "normalize::<{}>: obligations={:?}", - ::std::any::type_name::<T>(), + std::any::type_name::<T>(), normalizer.obligations, ); if normalizer.error { diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 038ba431c47..fdf1641c986 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -22,6 +22,7 @@ use super::SelectionCandidate::{self, *}; use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack}; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + #[instrument(level = "debug", skip(self))] pub(super) fn candidate_from_obligation<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -35,16 +36,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // this is because we want the unbound variables to be // replaced with fresh types starting from index 0. let cache_fresh_trait_pred = self.infcx.freshen(stack.obligation.predicate); - debug!( - "candidate_from_obligation(cache_fresh_trait_pred={:?}, obligation={:?})", - cache_fresh_trait_pred, stack - ); + debug!(?cache_fresh_trait_pred); debug_assert!(!stack.obligation.predicate.has_escaping_bound_vars()); if let Some(c) = self.check_candidate_cache(stack.obligation.param_env, cache_fresh_trait_pred) { - debug!("CACHE HIT: SELECT({:?})={:?}", cache_fresh_trait_pred, c); + debug!(candidate = ?c, "CACHE HIT"); return c; } @@ -57,7 +55,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let (candidate, dep_node) = self.in_task(|this| this.candidate_from_obligation_no_cache(stack)); - debug!("CACHE MISS: SELECT({:?})={:?}", cache_fresh_trait_pred, candidate); + debug!(?candidate, "CACHE MISS"); self.insert_candidate_cache( stack.obligation.param_env, cache_fresh_trait_pred, @@ -103,7 +101,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } else { IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } }; - debug!("evaluate_stack: pushing cause = {:?}", cause); + debug!(?cause, "evaluate_stack: pushing cause"); self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); } } @@ -120,7 +118,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let mut candidates = candidate_set.vec; - debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + debug!(?stack, ?candidates, "assembled {} candidates", candidates.len()); // At this point, we know that each of the entries in the // candidate set is *individually* applicable. Now we have to @@ -163,7 +161,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .flat_map(Result::transpose) .collect::<Result<Vec<_>, _>>()?; - debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len()); let needs_infer = stack.obligation.predicate.has_infer_types_or_consts(); @@ -181,10 +179,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); if is_dup { - debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + debug!(candidate = ?candidates[i], "Dropping candidate #{}/{}", i, candidates.len()); candidates.swap_remove(i); } else { - debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + debug!(candidate = ?candidates[i], "Retaining candidate #{}/{}", i, candidates.len()); i += 1; // If there are *STILL* multiple candidates, give up @@ -257,7 +255,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let lang_items = self.tcx().lang_items(); if lang_items.copy_trait() == Some(def_id) { - debug!("obligation self ty is {:?}", obligation.predicate.skip_binder().self_ty()); + debug!(obligation_self_ty = ?obligation.predicate.skip_binder().self_ty()); // User-defined copy impls are permitted, but only for // structs and enums. @@ -308,7 +306,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - debug!("assemble_candidates_for_projected_tys({:?})", obligation); + debug!(?obligation, "assemble_candidates_from_projected_tys"); // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. @@ -341,7 +339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { stack: &TraitObligationStack<'o, 'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_caller_bounds({:?})", stack.obligation); + debug!(?stack.obligation, "assemble_candidates_from_caller_bounds"); let all_bounds = stack .obligation @@ -383,10 +381,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let self_ty = obligation.self_ty().skip_binder(); match self_ty.kind() { ty::Generator(..) => { - debug!( - "assemble_generator_candidates: self_ty={:?} obligation={:?}", - self_ty, obligation - ); + debug!(?self_ty, ?obligation, "assemble_generator_candidates",); candidates.vec.push(GeneratorCandidate); } @@ -423,10 +418,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // type/region parameters match *obligation.self_ty().skip_binder().kind() { ty::Closure(_, closure_substs) => { - debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); + debug!(?kind, ?obligation, "assemble_unboxed_candidates"); match self.infcx.closure_kind(closure_substs) { Some(closure_kind) => { - debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind); + debug!(?closure_kind, "assemble_unboxed_candidates"); if closure_kind.extends(kind) { candidates.vec.push(ClosureCandidate); } @@ -503,7 +498,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) -> Result<(), SelectionError<'tcx>> { - debug!("assemble_candidates_from_impls(obligation={:?})", obligation); + debug!(?obligation, "assemble_candidates_from_impls"); // Essentially any user-written impl will match with an error type, // so creating `ImplCandidates` isn't useful. However, we might @@ -537,7 +532,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<(), SelectionError<'tcx>> { // Okay to skip binder here because the tests we do below do not involve bound regions. let self_ty = obligation.self_ty().skip_binder(); - debug!("assemble_candidates_from_auto_impls(self_ty={:?})", self_ty); + debug!(?self_ty, "assemble_candidates_from_auto_impls"); let def_id = obligation.predicate.def_id(); @@ -604,8 +599,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) { debug!( - "assemble_candidates_from_object_ty(self_ty={:?})", - obligation.self_ty().skip_binder() + self_ty = ?obligation.self_ty().skip_binder(), + "assemble_candidates_from_object_ty", ); self.infcx.probe(|_snapshot| { @@ -645,7 +640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => return, }; - debug!("assemble_candidates_from_object_ty: poly_trait_ref={:?}", poly_trait_ref); + debug!(?poly_trait_ref, "assemble_candidates_from_object_ty"); // Count only those upcast versions that match the trait-ref // we are looking for. Specifically, do not only check for the @@ -697,7 +692,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); - debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); + debug!(?source, ?target, "assemble_candidates_for_unsizing"); let may_apply = match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). @@ -758,7 +753,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<(), SelectionError<'tcx>> { // Okay to skip binder here because the tests we do below do not involve bound regions. let self_ty = obligation.self_ty().skip_binder(); - debug!("assemble_candidates_for_trait_alias(self_ty={:?})", self_ty); + debug!(?self_ty, "assemble_candidates_for_trait_alias"); let def_id = obligation.predicate.def_id(); @@ -778,7 +773,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) -> Result<(), SelectionError<'tcx>> { match conditions { BuiltinImplConditions::Where(nested) => { - debug!("builtin_bound: nested={:?}", nested); + debug!(?nested, "builtin_bound"); candidates .vec .push(BuiltinCandidate { has_nested: !nested.skip_binder().is_empty() }); diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 96f0bedf6f1..37d619d5942 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -42,13 +42,12 @@ use super::SelectionContext; use std::iter; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { + #[instrument(level = "debug", skip(self))] pub(super) fn confirm_candidate( &mut self, obligation: &TraitObligation<'tcx>, candidate: SelectionCandidate<'tcx>, ) -> Result<Selection<'tcx>, SelectionError<'tcx>> { - debug!("confirm_candidate({:?}, {:?})", obligation, candidate); - match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); @@ -191,7 +190,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, param: ty::PolyTraitRef<'tcx>, ) -> Vec<PredicateObligation<'tcx>> { - debug!("confirm_param_candidate({:?},{:?})", obligation, param); + debug!(?obligation, ?param, "confirm_param_candidate"); // During evaluation, we already checked that this // where-clause trait-ref could be unified with the obligation @@ -214,7 +213,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, has_nested: bool, ) -> ImplSourceBuiltinData<PredicateObligation<'tcx>> { - debug!("confirm_builtin_candidate({:?}, {:?})", obligation, has_nested); + debug!(?obligation, ?has_nested, "confirm_builtin_candidate"); let lang_items = self.tcx().lang_items(); let obligations = if has_nested { @@ -247,7 +246,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vec![] }; - debug!("confirm_builtin_candidate: obligations={:?}", obligations); + debug!(?obligations); ImplSourceBuiltinData { nested: obligations } } @@ -262,7 +261,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, trait_def_id: DefId, ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> { - debug!("confirm_auto_impl_candidate({:?}, {:?})", obligation, trait_def_id); + debug!(?obligation, ?trait_def_id, "confirm_auto_impl_candidate"); let types = obligation.predicate.map_bound(|inner| { let self_ty = self.infcx.shallow_resolve(inner.self_ty()); @@ -278,7 +277,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_def_id: DefId, nested: ty::Binder<Vec<Ty<'tcx>>>, ) -> ImplSourceAutoImplData<PredicateObligation<'tcx>> { - debug!("vtable_auto_impl: nested={:?}", nested); + debug!(?nested, "vtable_auto_impl"); ensure_sufficient_stack(|| { let cause = obligation.derived_cause(BuiltinDerivedObligation); let mut obligations = self.collect_predicates_for_types( @@ -308,7 +307,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // predicate as usual. It won't have any effect since auto traits are coinductive. obligations.extend(trait_obligations); - debug!("vtable_auto_impl: obligations={:?}", obligations); + debug!(?obligations, "vtable_auto_impl"); ImplSourceAutoImplData { trait_def_id, nested: obligations } }) @@ -319,13 +318,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, impl_def_id: DefId, ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_impl_candidate({:?},{:?})", obligation, impl_def_id); + debug!(?obligation, ?impl_def_id, "confirm_impl_candidate"); // First, create the substitutions by matching the impl again, // this time not in a probe. self.infcx.commit_unconditionally(|_| { let substs = self.rematch_impl(impl_def_id, obligation); - debug!("confirm_impl_candidate: substs={:?}", substs); + debug!(?substs, "impl substs"); let cause = obligation.derived_cause(ImplDerivedObligation); ensure_sufficient_stack(|| { self.vtable_impl( @@ -347,10 +346,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { recursion_depth: usize, param_env: ty::ParamEnv<'tcx>, ) -> ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>> { - debug!( - "vtable_impl(impl_def_id={:?}, substs={:?}, recursion_depth={})", - impl_def_id, substs, recursion_depth, - ); + debug!(?impl_def_id, ?substs, ?recursion_depth, "vtable_impl"); let mut impl_obligations = self.impl_or_trait_obligations( cause, @@ -360,10 +356,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &substs.value, ); - debug!( - "vtable_impl: impl_def_id={:?} impl_obligations={:?}", - impl_def_id, impl_obligations - ); + debug!(?impl_obligations, "vtable_impl"); // Because of RFC447, the impl-trait-ref and obligations // are sufficient to determine the impl substs, without @@ -379,8 +372,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, ) -> ImplSourceObjectData<'tcx, PredicateObligation<'tcx>> { + debug!(?obligation, "confirm_object_candidate"); let tcx = self.tcx(); - debug!("confirm_object_candidate({:?})", obligation); let trait_predicate = self.infcx.replace_bound_vars_with_placeholders(&obligation.predicate); @@ -507,7 +500,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - debug!("confirm_object_candidate: nested: {:?}", nested); + debug!(?nested, "object nested obligations"); ImplSourceObjectData { upcast_trait_ref, vtable_base, nested } } @@ -516,7 +509,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, ) -> Result<ImplSourceFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - debug!("confirm_fn_pointer_candidate({:?})", obligation); + debug!(?obligation, "confirm_fn_pointer_candidate"); // Okay to skip binder; it is reintroduced below. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); @@ -554,7 +547,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, alias_def_id: DefId, ) -> ImplSourceTraitAliasData<'tcx, PredicateObligation<'tcx>> { - debug!("confirm_trait_alias_candidate({:?}, {:?})", obligation, alias_def_id); + debug!(?obligation, ?alias_def_id, "confirm_trait_alias_candidate"); self.infcx.commit_unconditionally(|_| { let predicate = @@ -571,10 +564,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &substs, ); - debug!( - "confirm_trait_alias_candidate: trait_def_id={:?} trait_obligations={:?}", - trait_def_id, trait_obligations - ); + debug!(?trait_def_id, ?trait_obligations, "trait alias obligations"); ImplSourceTraitAliasData { alias_def_id, substs, nested: trait_obligations } }) @@ -594,7 +584,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { _ => bug!("closure candidate for non-closure {:?}", obligation), }; - debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, generator_def_id, substs); + debug!(?obligation, ?generator_def_id, ?substs, "confirm_generator_candidate"); let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs); let Normalized { value: trait_ref, mut obligations } = ensure_sufficient_stack(|| { @@ -607,11 +597,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); - debug!( - "confirm_generator_candidate(generator_def_id={:?}, \ - trait_ref={:?}, obligations={:?})", - generator_def_id, trait_ref, obligations - ); + debug!(?trait_ref, ?obligations, "generator candidate obligations"); obligations.extend(self.confirm_poly_trait_refs( obligation.cause.clone(), @@ -627,7 +613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { &mut self, obligation: &TraitObligation<'tcx>, ) -> Result<ImplSourceClosureData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>> { - debug!("confirm_closure_candidate({:?})", obligation); + debug!(?obligation, "confirm_closure_candidate"); let kind = self .tcx() @@ -654,10 +640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); - debug!( - "confirm_closure_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", - closure_def_id, trait_ref, obligations - ); + debug!(?closure_def_id, ?trait_ref, ?obligations, "confirm closure candidate obligations"); obligations.extend(self.confirm_poly_trait_refs( obligation.cause.clone(), @@ -731,7 +714,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let target = obligation.predicate.skip_binder().trait_ref.substs.type_at(1); let target = self.infcx.shallow_resolve(target); - debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); + debug!(?source, ?target, "confirm_builtin_unsize_candidate"); let mut nested = vec![]; match (source.kind(), target.kind()) { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a142ba58a69..4d347380c6c 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -236,7 +236,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, allow_negative_impls: bool, ) -> SelectionContext<'cx, 'tcx> { - debug!("with_negative({:?})", allow_negative_impls); + debug!(?allow_negative_impls, "with_negative"); SelectionContext { infcx, freshener: infcx.freshener(), @@ -251,7 +251,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { infcx: &'cx InferCtxt<'cx, 'tcx>, query_mode: TraitQueryMode, ) -> SelectionContext<'cx, 'tcx> { - debug!("with_query_mode({:?})", query_mode); + debug!(?query_mode, "with_query_mode"); SelectionContext { infcx, freshener: infcx.freshener(), @@ -290,10 +290,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx.tcx } - pub fn closure_typer(&self) -> &'cx InferCtxt<'cx, 'tcx> { - self.infcx - } - /////////////////////////////////////////////////////////////////////////// // Selection // @@ -311,11 +307,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Attempts to satisfy the obligation. If successful, this will affect the surrounding /// type environment by performing unification. + #[instrument(level = "debug", skip(self))] pub fn select( &mut self, obligation: &TraitObligation<'tcx>, ) -> SelectionResult<'tcx, Selection<'tcx>> { - debug!("select({:?})", obligation); debug_assert!(!obligation.predicate.has_escaping_bound_vars()); let pec = &ProvisionalEvaluationCache::default(); @@ -344,7 +340,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } Err(e) => Err(e), Ok(candidate) => { - debug!("select: candidate = {:?}", candidate); + debug!(?candidate); Ok(Some(candidate)) } } @@ -362,7 +358,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Evaluates whether the obligation `obligation` can be satisfied (by any means). pub fn predicate_may_hold_fatal(&mut self, obligation: &PredicateObligation<'tcx>) -> bool { - debug!("predicate_may_hold_fatal({:?})", obligation); + debug!(?obligation, "predicate_may_hold_fatal"); // This fatal query is a stopgap that should only be used in standard mode, // where we do not expect overflow to be propagated. @@ -419,10 +415,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { I: IntoIterator<Item = PredicateObligation<'tcx>> + std::fmt::Debug, { let mut result = EvaluatedToOk; - debug!("evaluate_predicates_recursively({:?})", predicates); + debug!(?predicates, "evaluate_predicates_recursively"); for obligation in predicates { let eval = self.evaluate_predicate_recursively(stack, obligation.clone())?; - debug!("evaluate_predicate_recursively({:?}) = {:?}", obligation, eval); if let EvaluatedToErr = eval { // fast-path - EvaluatedToErr is the top of the lattice, // so we don't need to look on the other predicates. @@ -434,17 +429,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(result) } + #[instrument( + level = "debug", + skip(self, previous_stack), + fields(previous_stack = ?previous_stack.head()) + )] fn evaluate_predicate_recursively<'o>( &mut self, previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: PredicateObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { - debug!( - "evaluate_predicate_recursively(obligation={:?}, previous_stack={:?})", - obligation, - previous_stack.head() - ); - // `previous_stack` stores a `TraitObligation`, while `obligation` is // a `PredicateObligation`. These are distinct types, so we can't // use any `Option` combinator method that would force them to be @@ -454,7 +448,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - ensure_sufficient_stack(|| { + let result = ensure_sufficient_stack(|| { match obligation.predicate.skip_binders() { ty::PredicateAtom::Trait(t, _) => { let t = ty::Binder::bind(t); @@ -561,10 +555,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } ty::PredicateAtom::ConstEquate(c1, c2) => { - debug!( - "evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", - c1, c2 - ); + debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts"); let evaluate = |c: &'tcx ty::Const<'tcx>| { if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { @@ -610,7 +601,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { bug!("TypeWellFormedFromEnv is only used for chalk") } } - }) + }); + + debug!(?result); + + result } fn evaluate_trait_predicate_recursively<'o>( @@ -618,7 +613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { previous_stack: TraitObligationStackList<'o, 'tcx>, mut obligation: TraitObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { - debug!("evaluate_trait_predicate_recursively({:?})", obligation); + debug!(?obligation, "evaluate_trait_predicate_recursively"); if !self.intercrate && obligation.is_global() @@ -627,19 +622,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // If a param env has no global bounds, global obligations do not // depend on its particular value in order to work, so we can clear // out the param env and get better caching. - debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation); + debug!("evaluate_trait_predicate_recursively - in global"); obligation.param_env = obligation.param_env.without_caller_bounds(); } let stack = self.push_stack(previous_stack, &obligation); let fresh_trait_ref = stack.fresh_trait_ref; + + debug!(?fresh_trait_ref); + if let Some(result) = self.check_evaluation_cache(obligation.param_env, fresh_trait_ref) { - debug!("CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); + debug!(?result, "CACHE HIT"); return Ok(result); } if let Some(result) = stack.cache().get_provisional(fresh_trait_ref) { - debug!("PROVISIONAL CACHE HIT: EVAL({:?})={:?}", fresh_trait_ref, result); + debug!(?result, "PROVISIONAL CACHE HIT"); stack.update_reached_depth(stack.cache().current_reached_depth()); return Ok(result); } @@ -662,7 +660,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let reached_depth = stack.reached_depth.get(); if reached_depth >= stack.depth { - debug!("CACHE MISS: EVAL({:?})={:?}", fresh_trait_ref, result); + debug!(?result, "CACHE MISS"); self.insert_evaluation_cache(obligation.param_env, fresh_trait_ref, dep_node, result); stack.cache().on_completion(stack.depth, |fresh_trait_ref, provisional_result| { @@ -674,7 +672,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); }); } else { - debug!("PROVISIONAL: {:?}={:?}", fresh_trait_ref, result); + debug!(?result, "PROVISIONAL"); debug!( "evaluate_trait_predicate_recursively: caching provisionally because {:?} \ is a cycle participant (at depth {}, reached depth {})", @@ -719,10 +717,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) .map(|stack| stack.depth) { - debug!( - "evaluate_stack({:?}) --> recursive at depth {}", - stack.fresh_trait_ref, cycle_depth, - ); + debug!("evaluate_stack --> recursive at depth {}", cycle_depth); // If we have a stack like `A B C D E A`, where the top of // the stack is the final `A`, then this will iterate over @@ -742,10 +737,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let cycle = cycle.map(|stack| stack.obligation.predicate.without_const().to_predicate(tcx)); if self.coinductive_match(cycle) { - debug!("evaluate_stack({:?}) --> recursive, coinductive", stack.fresh_trait_ref); + debug!("evaluate_stack --> recursive, coinductive"); Some(EvaluatedToOk) } else { - debug!("evaluate_stack({:?}) --> recursive, inductive", stack.fresh_trait_ref); + debug!("evaluate_stack --> recursive, inductive"); Some(EvaluatedToRecur) } } else { @@ -786,10 +781,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // This check was an imperfect workaround for a bug in the old // intercrate mode; it should be removed when that goes away. if unbound_input_types && self.intercrate { - debug!( - "evaluate_stack({:?}) --> unbound argument, intercrate --> ambiguous", - stack.fresh_trait_ref - ); + debug!("evaluate_stack --> unbound argument, intercrate --> ambiguous",); // Heuristics: show the diagnostics when there are no candidates in crate. if self.intercrate_ambiguity_causes.is_some() { debug!("evaluate_stack: intercrate_ambiguity_causes is some"); @@ -807,7 +799,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }, }); - debug!("evaluate_stack: pushing cause = {:?}", cause); + debug!(?cause, "evaluate_stack: pushing cause"); self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); } } @@ -824,10 +816,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }) { - debug!( - "evaluate_stack({:?}) --> unbound argument, recursive --> giving up", - stack.fresh_trait_ref - ); + debug!("evaluate_stack --> unbound argument, recursive --> giving up",); return Ok(EvaluatedToUnknown); } @@ -860,27 +849,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateAtom::Trait(ref data, _) => self.tcx().trait_is_auto(data.def_id()), _ => false, }; - debug!("coinductive_predicate({:?}) = {:?}", predicate, result); + debug!(?predicate, ?result, "coinductive_predicate"); result } /// Further evaluates `candidate` to decide whether all type parameters match and whether nested /// obligations are met. Returns whether `candidate` remains viable after this further /// scrutiny. + #[instrument( + level = "debug", + skip(self, stack), + fields(depth = stack.obligation.recursion_depth) + )] fn evaluate_candidate<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, candidate: &SelectionCandidate<'tcx>, ) -> Result<EvaluationResult, OverflowError> { - debug!( - "evaluate_candidate: depth={} candidate={:?}", - stack.obligation.recursion_depth, candidate - ); let result = self.evaluation_probe(|this| { let candidate = (*candidate).clone(); match this.confirm_candidate(stack.obligation, candidate) { Ok(selection) => { - debug!("evaluate_candidate: selection = {:?}", selection); + debug!(?selection); this.evaluate_predicates_recursively( stack.list(), selection.nested_obligations().into_iter(), @@ -889,10 +879,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Err(..) => Ok(EvaluatedToErr), } })?; - debug!( - "evaluate_candidate: depth={} result={:?}", - stack.obligation.recursion_depth, result - ); + debug!(?result); Ok(result) } @@ -925,10 +912,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if self.can_use_global_caches(param_env) { if !trait_ref.needs_infer() { - debug!( - "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, result, - ); + debug!(?trait_ref, ?result, "insert_evaluation_cache global"); // This may overwrite the cache with the same value // FIXME: Due to #50507 this overwrites the different values // This should be changed to use HashMapExt::insert_same @@ -938,7 +922,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - debug!("insert_evaluation_cache(trait_ref={:?}, candidate={:?})", trait_ref, result,); + debug!(?trait_ref, ?result, "insert_evaluation_cache"); self.infcx.evaluation_cache.insert(param_env.and(trait_ref), dep_node, result); } @@ -1127,11 +1111,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; if !self.can_cache_candidate(&candidate) { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?} -\ - candidate is not cacheable", - trait_ref, candidate - ); + debug!(?trait_ref, ?candidate, "insert_candidate_cache - candidate is not cacheable"); return; } @@ -1140,10 +1120,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Don't cache overflow globally; we only produce this in certain modes. } else if !trait_ref.needs_infer() { if !candidate.needs_infer() { - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) global", - trait_ref, candidate, - ); + debug!(?trait_ref, ?candidate, "insert_candidate_cache global"); // This may overwrite the cache with the same value. tcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate); return; @@ -1151,10 +1128,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } - debug!( - "insert_candidate_cache(trait_ref={:?}, candidate={:?}) local", - trait_ref, candidate, - ); + debug!(?trait_ref, ?candidate, "insert_candidate_cache local"); self.infcx.selection_cache.insert(param_env.and(trait_ref), dep_node, candidate); } @@ -1172,9 +1146,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let placeholder_trait_predicate = self.infcx().replace_bound_vars_with_placeholders(&poly_trait_predicate); debug!( - "match_projection_obligation_against_definition_bounds: \ - placeholder_trait_predicate={:?}", - placeholder_trait_predicate, + ?placeholder_trait_predicate, + "match_projection_obligation_against_definition_bounds" ); let tcx = self.infcx.tcx; @@ -1225,11 +1198,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }) .collect(); - debug!( - "match_projection_obligation_against_definition_bounds: \ - matching_bounds={:?}", - matching_bounds - ); + debug!(?matching_bounds, "match_projection_obligation_against_definition_bounds"); matching_bounds } @@ -1631,7 +1600,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::Closure(_, substs) => { // (*) binder moved here - Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect())) + let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); + if let ty::Infer(ty::TyVar(_)) = ty.kind() { + // Not yet resolved. + Ambiguous + } else { + Where(ty::Binder::bind(substs.as_closure().upvar_tys().collect())) + } } ty::Adt(..) | ty::Projection(..) | ty::Param(..) | ty::Opaque(..) => { @@ -1700,11 +1675,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { tys.iter().map(|k| k.expect_ty()).collect() } - ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().collect(), + ty::Closure(_, ref substs) => { + let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); + vec![ty] + } ty::Generator(_, ref substs, _) => { + let ty = self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); let witness = substs.as_generator().witness(); - substs.as_generator().upvar_tys().chain(iter::once(witness)).collect() + vec![ty].into_iter().chain(iter::once(witness)).collect() } ty::GeneratorWitness(types) => { @@ -1816,6 +1795,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { impl_def_id: DefId, obligation: &TraitObligation<'tcx>, ) -> Result<Normalized<'tcx, SubstsRef<'tcx>>, ()> { + debug!(?impl_def_id, ?obligation, "match_impl"); let impl_trait_ref = self.tcx().impl_trait_ref(impl_def_id).unwrap(); // Before we create the substitutions and everything, first @@ -1844,11 +1824,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) }); - debug!( - "match_impl(impl_def_id={:?}, obligation={:?}, \ - impl_trait_ref={:?}, placeholder_obligation_trait_ref={:?})", - impl_def_id, obligation, impl_trait_ref, placeholder_obligation_trait_ref - ); + debug!(?impl_trait_ref, ?placeholder_obligation_trait_ref); let InferOk { obligations, .. } = self .infcx @@ -1864,7 +1840,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - debug!("match_impl: success impl_substs={:?}", impl_substs); + debug!(?impl_substs, "match_impl: success"); Ok(Normalized { value: impl_substs, obligations: nested_obligations }) } @@ -1926,10 +1902,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tcx>, ) -> Result<Vec<PredicateObligation<'tcx>>, ()> { - debug!( - "match_poly_trait_ref: obligation={:?} poly_trait_ref={:?}", - obligation, poly_trait_ref - ); + debug!(?obligation, ?poly_trait_ref, "match_poly_trait_ref"); self.infcx .at(&obligation.cause, obligation.param_env) @@ -1976,10 +1949,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, substs: SubstsRef<'tcx>, ) -> ty::PolyTraitRef<'tcx> { - debug!("closure_trait_ref_unnormalized(obligation={:?}, substs={:?})", obligation, substs); + debug!(?obligation, ?substs, "closure_trait_ref_unnormalized"); let closure_sig = substs.as_closure().sig(); - debug!("closure_trait_ref_unnormalized: closure_sig = {:?}", closure_sig); + debug!(?closure_sig); // (1) Feels icky to skip the binder here, but OTOH we know // that the self-type is an unboxed closure type and hence is @@ -2030,7 +2003,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { def_id: DefId, // of impl or trait substs: SubstsRef<'tcx>, // for impl or trait ) -> Vec<PredicateObligation<'tcx>> { - debug!("impl_or_trait_obligations(def_id={:?})", def_id); + debug!(?def_id, "impl_or_trait_obligations"); let tcx = self.tcx(); // To allow for one-pass evaluation of the nested obligation, @@ -2152,10 +2125,10 @@ impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { self.depth, reached_depth, ); - debug!("update_reached_depth(reached_depth={})", reached_depth); + debug!(reached_depth, "update_reached_depth"); let mut p = self; while reached_depth < p.depth { - debug!("update_reached_depth: marking {:?} as cycle participant", p.fresh_trait_ref); + debug!(?p.fresh_trait_ref, "update_reached_depth: marking as cycle participant"); p.reached_depth.set(p.reached_depth.get().min(reached_depth)); p = p.previous.head.unwrap(); } @@ -2282,10 +2255,10 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { /// `self.current_reached_depth()` and above. fn get_provisional(&self, fresh_trait_ref: ty::PolyTraitRef<'tcx>) -> Option<EvaluationResult> { debug!( - "get_provisional(fresh_trait_ref={:?}) = {:#?} with reached-depth {}", - fresh_trait_ref, + ?fresh_trait_ref, + reached_depth = ?self.reached_depth.get(), + "get_provisional = {:#?}", self.map.borrow().get(&fresh_trait_ref), - self.reached_depth.get(), ); Some(self.map.borrow().get(&fresh_trait_ref)?.result) } @@ -2308,14 +2281,11 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { fresh_trait_ref: ty::PolyTraitRef<'tcx>, result: EvaluationResult, ) { - debug!( - "insert_provisional(from_dfn={}, reached_depth={}, fresh_trait_ref={:?}, result={:?})", - from_dfn, reached_depth, fresh_trait_ref, result, - ); + debug!(?from_dfn, ?reached_depth, ?fresh_trait_ref, ?result, "insert_provisional"); let r_d = self.reached_depth.get(); self.reached_depth.set(r_d.min(reached_depth)); - debug!("insert_provisional: reached_depth={:?}", self.reached_depth.get()); + debug!(reached_depth = self.reached_depth.get()); self.map.borrow_mut().insert(fresh_trait_ref, ProvisionalEvaluation { from_dfn, result }); } @@ -2329,7 +2299,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { /// these provisional entries must either depend on it or some /// ancestor of it. fn on_failure(&self, dfn: usize) { - debug!("on_failure(dfn={:?})", dfn,); + debug!(?dfn, "on_failure"); self.map.borrow_mut().retain(|key, eval| { if !eval.from_dfn >= dfn { debug!("on_failure: removing {:?}", key); @@ -2350,7 +2320,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { depth: usize, mut op: impl FnMut(ty::PolyTraitRef<'tcx>, EvaluationResult), ) { - debug!("on_completion(depth={}, reached_depth={})", depth, self.reached_depth.get(),); + debug!(?depth, reached_depth = ?self.reached_depth.get(), "on_completion"); if self.reached_depth.get() < depth { debug!("on_completion: did not yet reach depth to complete"); @@ -2358,7 +2328,7 @@ impl<'tcx> ProvisionalEvaluationCache<'tcx> { } for (fresh_trait_ref, eval) in self.map.borrow_mut().drain() { - debug!("on_completion: fresh_trait_ref={:?} eval={:?}", fresh_trait_ref, eval,); + debug!(?fresh_trait_ref, ?eval, "on_completion"); op(fresh_trait_ref, eval.result); } diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index d66bfd48206..496dff6c5b2 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -592,10 +592,8 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // anyway, except via auto trait matching (which // only inspects the upvar types). walker.skip_current_subtree(); // subtree handled below - for upvar_ty in substs.as_closure().upvar_tys() { - // FIXME(eddyb) add the type to `walker` instead of recursing. - self.compute(upvar_ty.into()); - } + // FIXME(eddyb) add the type to `walker` instead of recursing. + self.compute(substs.as_closure().tupled_upvars_ty().into()); } ty::FnPtr(_) => { diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index 3ee391d6dc7..6cffa6d02a4 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -210,12 +210,25 @@ fn dtorck_constraint_for_ty<'tcx>( Ok::<_, NoSolution>(()) })?, - ty::Closure(_, substs) => rustc_data_structures::stack::ensure_sufficient_stack(|| { - for ty in substs.as_closure().upvar_tys() { - dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; + ty::Closure(_, substs) => { + if !substs.as_closure().is_valid() { + // By the time this code runs, all type variables ought to + // be fully resolved. + + tcx.sess.delay_span_bug( + span, + &format!("upvar_tys for closure not found. Expected capture information for closure {}", ty,), + ); + return Err(NoSolution); } - Ok::<_, NoSolution>(()) - })?, + + rustc_data_structures::stack::ensure_sufficient_stack(|| { + for ty in substs.as_closure().upvar_tys() { + dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?; + } + Ok::<_, NoSolution>(()) + })? + } ty::Generator(_, substs, _movability) => { // rust-lang/rust#49918: types can be constructed, stored @@ -241,6 +254,16 @@ fn dtorck_constraint_for_ty<'tcx>( // derived from lifetimes attached to the upvars and resume // argument, and we *do* incorporate those here. + if !substs.as_generator().is_valid() { + // By the time this code runs, all type variables ought to + // be fully resolved. + tcx.sess.delay_span_bug( + span, + &format!("upvar_tys for generator not found. Expected capture information for generator {}", ty,), + ); + return Err(NoSolution); + } + constraints.outlives.extend( substs .as_generator() diff --git a/compiler/rustc_typeck/src/bounds.rs b/compiler/rustc_typeck/src/bounds.rs index 80f39051c58..683707470f4 100644 --- a/compiler/rustc_typeck/src/bounds.rs +++ b/compiler/rustc_typeck/src/bounds.rs @@ -72,7 +72,7 @@ impl<'tcx> Bounds<'tcx> { .iter() .map(|&(region_bound, span)| { let outlives = ty::OutlivesPredicate(param_ty, region_bound); - (ty::Binder::dummy(outlives).to_predicate(tcx), span) + (ty::Binder::bind(outlives).to_predicate(tcx), span) }) .chain(self.trait_bounds.iter().map(|&(bound_trait_ref, span, constness)| { let predicate = bound_trait_ref.with_constness(constness).to_predicate(tcx); diff --git a/compiler/rustc_typeck/src/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs index 740783aeb9d..a38fb9642b9 100644 --- a/compiler/rustc_typeck/src/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -285,10 +285,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let (fn_sig, def_span) = match *callee_ty.kind() { - ty::FnDef(def_id, _) => { - (callee_ty.fn_sig(self.tcx), self.tcx.hir().span_if_local(def_id)) - } + let (fn_sig, def_id) = match *callee_ty.kind() { + ty::FnDef(def_id, _) => (callee_ty.fn_sig(self.tcx), Some(def_id)), ty::FnPtr(sig) => (sig, None), ref t => { let mut unit_variant = None; @@ -427,7 +425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs, fn_sig.c_variadic, TupleArgumentsFlag::DontTupleArguments, - def_span, + def_id, ); fn_sig.output() diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index d319ac2cba6..3d8653b4a6a 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -29,7 +29,7 @@ pub fn check_wf_new(tcx: TyCtxt<'_>) { } pub(super) fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { - if !tcx.sess.target.target.is_abi_supported(abi) { + if !tcx.sess.target.is_abi_supported(abi) { struct_span_err!( tcx.sess, span, @@ -348,8 +348,7 @@ pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { check_packed(tcx, span, def); } -/// When the `#![feature(untagged_unions)]` gate is active, -/// check that the fields of the `union` does not contain fields that need dropping. +/// Check that the fields of the `union` do not need dropping. pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { let item_type = tcx.type_of(item_def_id); if let ty::Adt(def, substs) = item_type.kind() { diff --git a/compiler/rustc_typeck/src/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs index 8898a545228..8bdd933644a 100644 --- a/compiler/rustc_typeck/src/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -81,19 +81,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.closure_base_def_id(expr_def_id.to_def_id()), ); - let tupled_upvars_ty = - self.tcx.mk_tup(self.tcx.upvars_mentioned(expr_def_id).iter().flat_map(|upvars| { - upvars.iter().map(|(&var_hir_id, _)| { - // Create type variables (for now) to represent the transformed - // types of upvars. These will be unified during the upvar - // inference phase (`upvar.rs`). - self.infcx.next_ty_var(TypeVariableOrigin { - // FIXME(eddyb) distinguish upvar inference variables from the rest. - kind: TypeVariableOriginKind::ClosureSynthetic, - span: self.tcx.hir().span(var_hir_id), - }) - }) - })); + let tupled_upvars_ty = self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::ClosureSynthetic, + span: self.tcx.hir().span(expr.hir_id), + }); if let Some(GeneratorTypes { resume_ty, yield_ty, interior, movability }) = generator_types { diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 4addee1a4c9..db32a736181 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -39,6 +39,7 @@ use crate::astconv::AstConv; use crate::check::FnCtxt; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; +use rustc_hir::def_id::DefId; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; use rustc_middle::ty::adjustment::{ @@ -221,11 +222,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // unsafe qualifier. self.coerce_from_fn_pointer(a, a_f, b) } - ty::Closure(_, substs_a) => { + ty::Closure(closure_def_id_a, substs_a) => { // Non-capturing closures are coercible to // function pointers or unsafe function pointers. // It cannot convert closures that require unsafe. - self.coerce_closure_to_fn(a, substs_a, b) + self.coerce_closure_to_fn(a, closure_def_id_a, substs_a, b) } _ => { // Otherwise, just use unification rules. @@ -762,6 +763,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { fn coerce_closure_to_fn( &self, a: Ty<'tcx>, + closure_def_id_a: DefId, substs_a: SubstsRef<'tcx>, b: Ty<'tcx>, ) -> CoerceResult<'tcx> { @@ -772,7 +774,18 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let b = self.shallow_resolve(b); match b.kind() { - ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => { + // At this point we haven't done capture analysis, which means + // that the ClosureSubsts just contains an inference variable instead + // of tuple of captured types. + // + // All we care here is if any variable is being captured and not the exact paths, + // so we check `upvars_mentioned` for root variables being captured. + ty::FnPtr(fn_ty) + if self + .tcx + .upvars_mentioned(closure_def_id_a.expect_local()) + .map_or(true, |u| u.is_empty()) => + { // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` // to @@ -906,8 +919,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Function items or non-capturing closures of differing IDs or InternalSubsts. let (a_sig, b_sig) = { let is_capturing_closure = |ty| { - if let &ty::Closure(_, substs) = ty { - substs.as_closure().upvar_tys().next().is_some() + if let &ty::Closure(closure_def_id, _substs) = ty { + self.tcx.upvars_mentioned(closure_def_id.expect_local()).is_some() } else { false } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs deleted file mode 100644 index 79d6c7dbfda..00000000000 --- a/compiler/rustc_typeck/src/check/fn_ctxt.rs +++ /dev/null @@ -1,3200 +0,0 @@ -// ignore-tidy-filelength -// FIXME: This file seems to have too much functionality wrapped into it, -// leading to it being too long. -// Splitting this file may involve abstracting functionality into other files. - -use super::callee::{self, DeferredCallResolution}; -use super::coercion::{CoerceMany, DynamicCoerceMany}; -use super::method::{self, MethodCallee, SelfSource}; -use super::Expectation::*; -use super::TupleArgumentsFlag::*; -use super::{ - potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, EnclosingBreakables, - Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, UnsafetyState, -}; -use crate::astconv::{ - AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, -}; - -use rustc_ast as ast; -use rustc_ast::util::parser::ExprPrecedence; -use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; -use rustc_errors::ErrorReported; -use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; -use rustc_hir as hir; -use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::DefId; -use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, GenericArg, ItemKind, Node, QPath}; -use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; -use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; -use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_infer::infer::{self, InferOk, InferResult}; -use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::ty::adjustment::{ - Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, -}; -use rustc_middle::ty::fold::TypeFoldable; -use rustc_middle::ty::subst::{ - self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, -}; -use rustc_middle::ty::{ - self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, ToPolyTraitRef, - ToPredicate, Ty, TyCtxt, UserType, -}; -use rustc_session::{lint, Session}; -use rustc_span::hygiene::DesugaringKind; -use rustc_span::source_map::{original_sp, DUMMY_SP}; -use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{self, BytePos, MultiSpan, Span}; -use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::opaque_types::InferCtxtExt as _; -use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; -use rustc_trait_selection::traits::{ - self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, -}; - -use std::cell::{Cell, RefCell}; -use std::collections::hash_map::Entry; -use std::iter; -use std::mem::replace; -use std::ops::Deref; -use std::slice; - -pub struct FnCtxt<'a, 'tcx> { - pub(super) body_id: hir::HirId, - - /// The parameter environment used for proving trait obligations - /// in this function. This can change when we descend into - /// closures (as they bring new things into scope), hence it is - /// not part of `Inherited` (as of the time of this writing, - /// closures do not yet change the environment, but they will - /// eventually). - pub(super) param_env: ty::ParamEnv<'tcx>, - - /// Number of errors that had been reported when we started - /// checking this function. On exit, if we find that *more* errors - /// have been reported, we will skip regionck and other work that - /// expects the types within the function to be consistent. - // FIXME(matthewjasper) This should not exist, and it's not correct - // if type checking is run in parallel. - err_count_on_creation: usize, - - /// If `Some`, this stores coercion information for returned - /// expressions. If `None`, this is in a context where return is - /// inappropriate, such as a const expression. - /// - /// This is a `RefCell<DynamicCoerceMany>`, which means that we - /// can track all the return expressions and then use them to - /// compute a useful coercion from the set, similar to a match - /// expression or other branching context. You can use methods - /// like `expected_ty` to access the declared return type (if - /// any). - pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>, - - pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>, - - pub(super) ret_type_span: Option<Span>, - - /// Used exclusively to reduce cost of advanced evaluation used for - /// more helpful diagnostics. - pub(super) in_tail_expr: bool, - - /// First span of a return site that we find. Used in error messages. - pub(super) ret_coercion_span: RefCell<Option<Span>>, - - pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, - - pub(super) ps: RefCell<UnsafetyState>, - - /// Whether the last checked node generates a divergence (e.g., - /// `return` will set this to `Always`). In general, when entering - /// an expression or other node in the tree, the initial value - /// indicates whether prior parts of the containing expression may - /// have diverged. It is then typically set to `Maybe` (and the - /// old value remembered) for processing the subparts of the - /// current expression. As each subpart is processed, they may set - /// the flag to `Always`, etc. Finally, at the end, we take the - /// result and "union" it with the original value, so that when we - /// return the flag indicates if any subpart of the parent - /// expression (up to and including this part) has diverged. So, - /// if you read it after evaluating a subexpression `X`, the value - /// you get indicates whether any subexpression that was - /// evaluating up to and including `X` diverged. - /// - /// We currently use this flag only for diagnostic purposes: - /// - /// - To warn about unreachable code: if, after processing a - /// sub-expression but before we have applied the effects of the - /// current node, we see that the flag is set to `Always`, we - /// can issue a warning. This corresponds to something like - /// `foo(return)`; we warn on the `foo()` expression. (We then - /// update the flag to `WarnedAlways` to suppress duplicate - /// reports.) Similarly, if we traverse to a fresh statement (or - /// tail expression) from a `Always` setting, we will issue a - /// warning. This corresponds to something like `{return; - /// foo();}` or `{return; 22}`, where we would warn on the - /// `foo()` or `22`. - /// - /// An expression represents dead code if, after checking it, - /// the diverges flag is set to something other than `Maybe`. - pub(super) diverges: Cell<Diverges>, - - /// Whether any child nodes have any type errors. - pub(super) has_errors: Cell<bool>, - - pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>, - - pub(super) inh: &'a Inherited<'a, 'tcx>, -} - -impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - pub fn new( - inh: &'a Inherited<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - body_id: hir::HirId, - ) -> FnCtxt<'a, 'tcx> { - FnCtxt { - body_id, - param_env, - err_count_on_creation: inh.tcx.sess.err_count(), - ret_coercion: None, - ret_coercion_impl_trait: None, - ret_type_span: None, - in_tail_expr: false, - ret_coercion_span: RefCell::new(None), - resume_yield_tys: None, - ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), - diverges: Cell::new(Diverges::Maybe), - has_errors: Cell::new(false), - enclosing_breakables: RefCell::new(EnclosingBreakables { - stack: Vec::new(), - by_id: Default::default(), - }), - inh, - } - } - - pub fn sess(&self) -> &Session { - &self.tcx.sess - } - - pub fn errors_reported_since_creation(&self) -> bool { - self.tcx.sess.err_count() > self.err_count_on_creation - } - - /// Produces warning on the given node, if the current point in the - /// function is unreachable, and there hasn't been another warning. - pub(super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { - // FIXME: Combine these two 'if' expressions into one once - // let chains are implemented - if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { - // If span arose from a desugaring of `if` or `while`, then it is the condition itself, - // which diverges, that we are about to lint on. This gives suboptimal diagnostics. - // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. - if !span.is_desugaring(DesugaringKind::CondTemporary) - && !span.is_desugaring(DesugaringKind::Async) - && !orig_span.is_desugaring(DesugaringKind::Await) - { - self.diverges.set(Diverges::WarnedAlways); - - debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - - self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { - let msg = format!("unreachable {}", kind); - lint.build(&msg) - .span_label(span, &msg) - .span_label( - orig_span, - custom_note - .unwrap_or("any code following this expression is unreachable"), - ) - .emit(); - }) - } - } - } - - pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { - ObligationCause::new(span, self.body_id, code) - } - - pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { - self.cause(span, ObligationCauseCode::MiscObligation) - } - - /// Resolves type and const variables in `ty` if possible. Unlike the infcx - /// version (resolve_vars_if_possible), this version will - /// also select obligations if it seems useful, in an effort - /// to get more type information. - pub(super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { - debug!("resolve_vars_with_obligations(ty={:?})", ty); - - // No Infer()? Nothing needs doing. - if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); - return ty; - } - - // If `ty` is a type variable, see whether we already know what it is. - ty = self.resolve_vars_if_possible(&ty); - if !ty.has_infer_types_or_consts() { - debug!("resolve_vars_with_obligations: ty={:?}", ty); - return ty; - } - - // If not, try resolving pending obligations as much as - // possible. This can help substantially when there are - // indirect dependencies that don't seem worth tracking - // precisely. - self.select_obligations_where_possible(false, |_| {}); - ty = self.resolve_vars_if_possible(&ty); - - debug!("resolve_vars_with_obligations: ty={:?}", ty); - ty - } - - pub(super) fn record_deferred_call_resolution( - &self, - closure_def_id: DefId, - r: DeferredCallResolution<'tcx>, - ) { - let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.entry(closure_def_id).or_default().push(r); - } - - pub(super) fn remove_deferred_call_resolutions( - &self, - closure_def_id: DefId, - ) -> Vec<DeferredCallResolution<'tcx>> { - let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); - deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![]) - } - - pub fn tag(&self) -> String { - format!("{:p}", self) - } - - pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> { - self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| { - span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid)) - }) - } - - #[inline] - pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { - debug!( - "write_ty({:?}, {:?}) in fcx {}", - id, - self.resolve_vars_if_possible(&ty), - self.tag() - ); - self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); - - if ty.references_error() { - self.has_errors.set(true); - self.set_tainted_by_errors(); - } - } - - pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) { - self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index); - } - - fn write_resolution(&self, hir_id: hir::HirId, r: Result<(DefKind, DefId), ErrorReported>) { - self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); - } - - pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { - debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); - self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); - self.write_substs(hir_id, method.substs); - - // When the method is confirmed, the `method.substs` includes - // parameters from not just the method, but also the impl of - // the method -- in particular, the `Self` type will be fully - // resolved. However, those are not something that the "user - // specified" -- i.e., those types come from the inferred type - // of the receiver, not something the user wrote. So when we - // create the user-substs, we want to replace those earlier - // types with just the types that the user actually wrote -- - // that is, those that appear on the *method itself*. - // - // As an example, if the user wrote something like - // `foo.bar::<u32>(...)` -- the `Self` type here will be the - // type of `foo` (possibly adjusted), but we don't want to - // include that. We want just the `[_, u32]` part. - if !method.substs.is_noop() { - let method_generics = self.tcx.generics_of(method.def_id); - if !method_generics.params.is_empty() { - let user_type_annotation = self.infcx.probe(|_| { - let user_substs = UserSubsts { - substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| { - let i = param.index as usize; - if i < method_generics.parent_count { - self.infcx.var_for_def(DUMMY_SP, param) - } else { - method.substs[i] - } - }), - user_self_ty: None, // not relevant here - }; - - self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( - method.def_id, - user_substs, - )) - }); - - debug!("write_method_call: user_type_annotation={:?}", user_type_annotation); - self.write_user_type_annotation(hir_id, user_type_annotation); - } - } - } - - pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) { - if !substs.is_noop() { - debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag()); - - self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs); - } - } - - /// Given the substs that we just converted from the HIR, try to - /// canonicalize them and store them as user-given substitutions - /// (i.e., substitutions that must be respected by the NLL check). - /// - /// This should be invoked **before any unifications have - /// occurred**, so that annotations like `Vec<_>` are preserved - /// properly. - pub fn write_user_type_annotation_from_substs( - &self, - hir_id: hir::HirId, - def_id: DefId, - substs: SubstsRef<'tcx>, - user_self_ty: Option<UserSelfTy<'tcx>>, - ) { - debug!( - "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ - user_self_ty={:?} in fcx {}", - hir_id, - def_id, - substs, - user_self_ty, - self.tag(), - ); - - if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { - let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( - def_id, - UserSubsts { substs, user_self_ty }, - )); - debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); - self.write_user_type_annotation(hir_id, canonicalized); - } - } - - pub fn write_user_type_annotation( - &self, - hir_id: hir::HirId, - canonical_user_type_annotation: CanonicalUserType<'tcx>, - ) { - debug!( - "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", - hir_id, - canonical_user_type_annotation, - self.tag(), - ); - - if !canonical_user_type_annotation.is_identity() { - self.typeck_results - .borrow_mut() - .user_provided_types_mut() - .insert(hir_id, canonical_user_type_annotation); - } else { - debug!("write_user_type_annotation: skipping identity substs"); - } - } - - pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) { - debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); - - if adj.is_empty() { - return; - } - - let autoborrow_mut = adj.iter().any(|adj| { - matches!(adj, &Adjustment { - kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), - .. - }) - }); - - match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) { - Entry::Vacant(entry) => { - entry.insert(adj); - } - Entry::Occupied(mut entry) => { - debug!(" - composing on top of {:?}", entry.get()); - match (&entry.get()[..], &adj[..]) { - // Applying any adjustment on top of a NeverToAny - // is a valid NeverToAny adjustment, because it can't - // be reached. - (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return, - (&[ - Adjustment { kind: Adjust::Deref(_), .. }, - Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, - ], &[ - Adjustment { kind: Adjust::Deref(_), .. }, - .. // Any following adjustments are allowed. - ]) => { - // A reborrow has no effect before a dereference. - } - // FIXME: currently we never try to compose autoderefs - // and ReifyFnPointer/UnsafeFnPointer, but we could. - _ => - bug!("while adjusting {:?}, can't compose {:?} and {:?}", - expr, entry.get(), adj) - }; - *entry.get_mut() = adj; - } - } - - // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`. - // In this case implicit use of `Deref` and `Index` within `<expr>` should - // instead be `DerefMut` and `IndexMut`, so fix those up. - if autoborrow_mut { - self.convert_place_derefs_to_mutable(expr); - } - } - - /// Basically whenever we are converting from a type scheme into - /// the fn body space, we always want to normalize associated - /// types as well. This function combines the two. - fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T - where - T: TypeFoldable<'tcx>, - { - let value = value.subst(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &value); - debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result); - result - } - - /// As `instantiate_type_scheme`, but for the bounds found in a - /// generic type scheme. - fn instantiate_bounds( - &self, - span: Span, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) { - let bounds = self.tcx.predicates_of(def_id); - let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect(); - let result = bounds.instantiate(self.tcx, substs); - let result = self.normalize_associated_types_in(span, &result); - debug!( - "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}", - bounds, substs, result, spans, - ); - (result, spans) - } - - /// Replaces the opaque types from the given value with type variables, - /// and records the `OpaqueTypeMap` for later use during writeback. See - /// `InferCtxt::instantiate_opaque_types` for more details. - pub(super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>( - &self, - parent_id: hir::HirId, - value: &T, - value_span: Span, - ) -> T { - let parent_def_id = self.tcx.hir().local_def_id(parent_id); - debug!( - "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", - parent_def_id, value - ); - - let (value, opaque_type_map) = - self.register_infer_ok_obligations(self.instantiate_opaque_types( - parent_def_id, - self.body_id, - self.param_env, - value, - value_span, - )); - - let mut opaque_types = self.opaque_types.borrow_mut(); - let mut opaque_types_vars = self.opaque_types_vars.borrow_mut(); - for (ty, decl) in opaque_type_map { - let _ = opaque_types.insert(ty, decl); - let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); - } - - value - } - - pub(super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T - where - T: TypeFoldable<'tcx>, - { - self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) - } - - pub(super) fn normalize_associated_types_in_as_infer_ok<T>( - &self, - span: Span, - value: &T, - ) -> InferOk<'tcx, T> - where - T: TypeFoldable<'tcx>, - { - self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value) - } - - pub fn require_type_meets( - &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - def_id: DefId, - ) { - self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code)); - } - - pub fn require_type_is_sized( - &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - if !ty.references_error() { - let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - self.require_type_meets(ty, span, code, lang_item); - } - } - - pub fn require_type_is_sized_deferred( - &self, - ty: Ty<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - if !ty.references_error() { - self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); - } - } - - pub fn register_bound( - &self, - ty: Ty<'tcx>, - def_id: DefId, - cause: traits::ObligationCause<'tcx>, - ) { - if !ty.references_error() { - self.fulfillment_cx.borrow_mut().register_bound( - self, - self.param_env, - ty, - def_id, - cause, - ); - } - } - - pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { - let t = AstConv::ast_ty_to_ty(self, ast_t); - self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); - t - } - - pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { - let ty = self.to_ty(ast_ty); - debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); - - if Self::can_contain_user_lifetime_bounds(ty) { - let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty)); - debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); - self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); - } - - ty - } - - pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { - let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); - let c = ty::Const::from_anon_const(self.tcx, const_def_id); - self.register_wf_obligation( - c.into(), - self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::MiscObligation, - ); - c - } - - pub fn const_arg_to_const( - &self, - ast_c: &hir::AnonConst, - param_def_id: DefId, - ) -> &'tcx ty::Const<'tcx> { - let const_def = ty::WithOptConstParam { - did: self.tcx.hir().local_def_id(ast_c.hir_id), - const_param_did: Some(param_def_id), - }; - let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def); - self.register_wf_obligation( - c.into(), - self.tcx.hir().span(ast_c.hir_id), - ObligationCauseCode::MiscObligation, - ); - c - } - - // If the type given by the user has free regions, save it for later, since - // NLL would like to enforce those. Also pass in types that involve - // projections, since those can resolve to `'static` bounds (modulo #54940, - // which hopefully will be fixed by the time you see this comment, dear - // reader, although I have my doubts). Also pass in types with inference - // types, because they may be repeated. Other sorts of things are already - // sufficiently enforced with erased regions. =) - fn can_contain_user_lifetime_bounds<T>(t: T) -> bool - where - T: TypeFoldable<'tcx>, - { - t.has_free_regions() || t.has_projections() || t.has_infer_types() - } - - pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { - match self.typeck_results.borrow().node_types().get(id) { - Some(&t) => t, - None if self.is_tainted_by_errors() => self.tcx.ty_error(), - None => { - bug!( - "no type for node {}: {} in fcx {}", - id, - self.tcx.hir().node_to_string(id), - self.tag() - ); - } - } - } - - /// Registers an obligation for checking later, during regionck, that `arg` is well-formed. - pub fn register_wf_obligation( - &self, - arg: subst::GenericArg<'tcx>, - span: Span, - code: traits::ObligationCauseCode<'tcx>, - ) { - // WF obligations never themselves fail, so no real need to give a detailed cause: - let cause = traits::ObligationCause::new(span, self.body_id, code); - self.register_predicate(traits::Obligation::new( - cause, - self.param_env, - ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx), - )); - } - - /// Registers obligations that all `substs` are well-formed. - pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { - for arg in substs.iter().filter(|arg| { - matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) - }) { - self.register_wf_obligation(arg, expr.span, traits::MiscObligation); - } - } - - /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each - /// type/region parameter was instantiated (`substs`), creates and registers suitable - /// trait/region obligations. - /// - /// For example, if there is a function: - /// - /// ``` - /// fn foo<'a,T:'a>(...) - /// ``` - /// - /// and a reference: - /// - /// ``` - /// let f = foo; - /// ``` - /// - /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a` - /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally. - pub fn add_obligations_for_parameters( - &self, - cause: traits::ObligationCause<'tcx>, - predicates: ty::InstantiatedPredicates<'tcx>, - ) { - assert!(!predicates.has_escaping_bound_vars()); - - debug!("add_obligations_for_parameters(predicates={:?})", predicates); - - for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) { - self.register_predicate(obligation); - } - } - - // FIXME(arielb1): use this instead of field.ty everywhere - // Only for fields! Returns <none> for methods> - // Indifferent to privacy flags - pub fn field_ty( - &self, - span: Span, - field: &'tcx ty::FieldDef, - substs: SubstsRef<'tcx>, - ) -> Ty<'tcx> { - self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) - } - - pub(super) fn check_casts(&self) { - let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); - for cast in deferred_cast_checks.drain(..) { - cast.check(self); - } - } - - pub(super) fn resolve_generator_interiors(&self, def_id: DefId) { - let mut generators = self.deferred_generator_interiors.borrow_mut(); - for (body_id, interior, kind) in generators.drain(..) { - self.select_obligations_where_possible(false, |_| {}); - super::generator_interior::resolve_interior(self, def_id, body_id, interior, kind); - } - } - - // Tries to apply a fallback to `ty` if it is an unsolved variable. - // - // - Unconstrained ints are replaced with `i32`. - // - // - Unconstrained floats are replaced with with `f64`. - // - // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` - // is enabled. Otherwise, they are replaced with `()`. - // - // Fallback becomes very dubious if we have encountered type-checking errors. - // In that case, fallback to Error. - // The return value indicates whether fallback has occurred. - pub(super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { - use rustc_middle::ty::error::UnconstrainedNumeric::Neither; - use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; - - assert!(ty.is_ty_infer()); - let fallback = match self.type_is_unconstrained_numeric(ty) { - _ if self.is_tainted_by_errors() => self.tcx().ty_error(), - UnconstrainedInt => self.tcx.types.i32, - UnconstrainedFloat => self.tcx.types.f64, - Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), - Neither => { - // This type variable was created from the instantiation of an opaque - // type. The fact that we're attempting to perform fallback for it - // means that the function neither constrained it to a concrete - // type, nor to the opaque type itself. - // - // For example, in this code: - // - //``` - // type MyType = impl Copy; - // fn defining_use() -> MyType { true } - // fn other_use() -> MyType { defining_use() } - // ``` - // - // `defining_use` will constrain the instantiated inference - // variable to `bool`, while `other_use` will constrain - // the instantiated inference variable to `MyType`. - // - // When we process opaque types during writeback, we - // will handle cases like `other_use`, and not count - // them as defining usages - // - // However, we also need to handle cases like this: - // - // ```rust - // pub type Foo = impl Copy; - // fn produce() -> Option<Foo> { - // None - // } - // ``` - // - // In the above snippet, the inference variable created by - // instantiating `Option<Foo>` will be completely unconstrained. - // We treat this as a non-defining use by making the inference - // variable fall back to the opaque type itself. - if let FallbackMode::All = mode { - if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { - debug!( - "fallback_if_possible: falling back opaque type var {:?} to {:?}", - ty, opaque_ty - ); - *opaque_ty - } else { - return false; - } - } else { - return false; - } - } - }; - debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); - self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback); - true - } - - pub(super) fn select_all_obligations_or_error(&self) { - debug!("select_all_obligations_or_error"); - if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { - self.report_fulfillment_errors(&errors, self.inh.body_id, false); - } - } - - /// Select as many obligations as we can at present. - pub(super) fn select_obligations_where_possible( - &self, - fallback_has_occurred: bool, - mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>), - ) { - let result = self.fulfillment_cx.borrow_mut().select_where_possible(self); - if let Err(mut errors) = result { - mutate_fullfillment_errors(&mut errors); - self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); - } - } - - /// For the overloaded place expressions (`*x`, `x[3]`), the trait - /// returns a type of `&T`, but the actual type we assign to the - /// *expression* is `T`. So this function just peels off the return - /// type by one layer to yield `T`. - pub(super) fn make_overloaded_place_return_type( - &self, - method: MethodCallee<'tcx>, - ) -> ty::TypeAndMut<'tcx> { - // extract method return type, which will be &T; - let ret_ty = method.sig.output(); - - // method returns &T, but the type as visible to user is T, so deref - ret_ty.builtin_deref(true).unwrap() - } - - pub(super) fn check_method_argument_types( - &self, - sp: Span, - expr: &'tcx hir::Expr<'tcx>, - method: Result<MethodCallee<'tcx>, ()>, - args_no_rcvr: &'tcx [hir::Expr<'tcx>], - tuple_arguments: TupleArgumentsFlag, - expected: Expectation<'tcx>, - ) -> Ty<'tcx> { - let has_error = match method { - Ok(method) => method.substs.references_error() || method.sig.references_error(), - Err(_) => true, - }; - if has_error { - let err_inputs = self.err_args(args_no_rcvr.len()); - - let err_inputs = match tuple_arguments { - DontTupleArguments => err_inputs, - TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])], - }; - - self.check_argument_types( - sp, - expr, - &err_inputs[..], - &[], - args_no_rcvr, - false, - tuple_arguments, - None, - ); - return self.tcx.ty_error(); - } - - let method = method.unwrap(); - // HACK(eddyb) ignore self in the definition (see above). - let expected_arg_tys = self.expected_inputs_for_expected_output( - sp, - expected, - method.sig.output(), - &method.sig.inputs()[1..], - ); - self.check_argument_types( - sp, - expr, - &method.sig.inputs()[1..], - &expected_arg_tys[..], - args_no_rcvr, - method.sig.c_variadic, - tuple_arguments, - self.tcx.hir().span_if_local(method.def_id), - ); - method.sig.output() - } - - fn self_type_matches_expected_vid( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - expected_vid: ty::TyVid, - ) -> bool { - let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); - debug!( - "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", - trait_ref, self_ty, expected_vid - ); - match *self_ty.kind() { - ty::Infer(ty::TyVar(found_vid)) => { - // FIXME: consider using `sub_root_var` here so we - // can see through subtyping. - let found_vid = self.root_var(found_vid); - debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); - expected_vid == found_vid - } - _ => false, - } - } - - pub(super) fn obligations_for_self_ty<'b>( - &'b self, - self_ty: ty::TyVid, - ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)> - + Captures<'tcx> - + 'b { - // FIXME: consider using `sub_root_var` here so we - // can see through subtyping. - let ty_var_root = self.root_var(self_ty); - debug!( - "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", - self_ty, - ty_var_root, - self.fulfillment_cx.borrow().pending_obligations() - ); - - self.fulfillment_cx - .borrow() - .pending_obligations() - .into_iter() - .filter_map(move |obligation| { - match obligation.predicate.skip_binders() { - ty::PredicateAtom::Projection(data) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation)) - } - ty::PredicateAtom::Trait(data, _) => { - Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation)) - } - ty::PredicateAtom::Subtype(..) => None, - ty::PredicateAtom::RegionOutlives(..) => None, - ty::PredicateAtom::TypeOutlives(..) => None, - ty::PredicateAtom::WellFormed(..) => None, - ty::PredicateAtom::ObjectSafe(..) => None, - ty::PredicateAtom::ConstEvaluatable(..) => None, - ty::PredicateAtom::ConstEquate(..) => None, - // N.B., this predicate is created by breaking down a - // `ClosureType: FnFoo()` predicate, where - // `ClosureType` represents some `Closure`. It can't - // possibly be referring to the current closure, - // because we haven't produced the `Closure` for - // this closure yet; this is exactly why the other - // code is looking for a self type of a unresolved - // inference variable. - ty::PredicateAtom::ClosureKind(..) => None, - ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, - } - }) - .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) - } - - pub(super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { - self.obligations_for_self_ty(self_ty) - .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait()) - } - - /// Generic function that factors out common logic from function calls, - /// method calls and overloaded operators. - pub(super) fn check_argument_types( - &self, - sp: Span, - expr: &'tcx hir::Expr<'tcx>, - fn_inputs: &[Ty<'tcx>], - expected_arg_tys: &[Ty<'tcx>], - args: &'tcx [hir::Expr<'tcx>], - c_variadic: bool, - tuple_arguments: TupleArgumentsFlag, - def_span: Option<Span>, - ) { - let tcx = self.tcx; - // Grab the argument types, supplying fresh type variables - // if the wrong number of arguments were supplied - let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 }; - - // All the input types from the fn signature must outlive the call - // so as to validate implied bounds. - for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { - self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); - } - - let expected_arg_count = fn_inputs.len(); - - let param_count_error = |expected_count: usize, - arg_count: usize, - error_code: &str, - c_variadic: bool, - sugg_unit: bool| { - let (span, start_span, args) = match &expr.kind { - hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]), - hir::ExprKind::MethodCall(path_segment, span, args, _) => ( - *span, - // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. - path_segment - .args - .and_then(|args| args.args.iter().last()) - // Account for `foo.bar::<T>()`. - .map(|arg| { - // Skip the closing `>`. - tcx.sess - .source_map() - .next_point(tcx.sess.source_map().next_point(arg.span())) - }) - .unwrap_or(*span), - &args[1..], // Skip the receiver. - ), - k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k), - }; - let arg_spans = if args.is_empty() { - // foo() - // ^^^-- supplied 0 arguments - // | - // expected 2 arguments - vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())] - } else { - // foo(1, 2, 3) - // ^^^ - - - supplied 3 arguments - // | - // expected 2 arguments - args.iter().map(|arg| arg.span).collect::<Vec<Span>>() - }; - - let mut err = tcx.sess.struct_span_err_with_code( - span, - &format!( - "this function takes {}{} but {} {} supplied", - if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "argument"), - potentially_plural_count(arg_count, "argument"), - if arg_count == 1 { "was" } else { "were" } - ), - DiagnosticId::Error(error_code.to_owned()), - ); - let label = format!("supplied {}", potentially_plural_count(arg_count, "argument")); - for (i, span) in arg_spans.into_iter().enumerate() { - err.span_label( - span, - if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, - ); - } - - if let Some(def_s) = def_span.map(|sp| tcx.sess.source_map().guess_head_span(sp)) { - err.span_label(def_s, "defined here"); - } - if sugg_unit { - let sugg_span = tcx.sess.source_map().end_point(expr.span); - // remove closing `)` from the span - let sugg_span = sugg_span.shrink_to_lo(); - err.span_suggestion( - sugg_span, - "expected the unit value `()`; create it with empty parentheses", - String::from("()"), - Applicability::MachineApplicable, - ); - } else { - err.span_label( - span, - format!( - "expected {}{}", - if c_variadic { "at least " } else { "" }, - potentially_plural_count(expected_count, "argument") - ), - ); - } - err.emit(); - }; - - let mut expected_arg_tys = expected_arg_tys.to_vec(); - - let formal_tys = if tuple_arguments == TupleArguments { - let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); - match tuple_type.kind() { - ty::Tuple(arg_types) if arg_types.len() != args.len() => { - param_count_error(arg_types.len(), args.len(), "E0057", false, false); - expected_arg_tys = vec![]; - self.err_args(args.len()) - } - ty::Tuple(arg_types) => { - expected_arg_tys = match expected_arg_tys.get(0) { - Some(&ty) => match ty.kind() { - ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), - _ => vec![], - }, - None => vec![], - }; - arg_types.iter().map(|k| k.expect_ty()).collect() - } - _ => { - struct_span_err!( - tcx.sess, - sp, - E0059, - "cannot use call notation; the first type parameter \ - for the function trait is neither a tuple nor unit" - ) - .emit(); - expected_arg_tys = vec![]; - self.err_args(args.len()) - } - } - } else if expected_arg_count == supplied_arg_count { - fn_inputs.to_vec() - } else if c_variadic { - if supplied_arg_count >= expected_arg_count { - fn_inputs.to_vec() - } else { - param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) - } - } else { - // is the missing argument of type `()`? - let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit() - } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { - self.resolve_vars_if_possible(&fn_inputs[0]).is_unit() - } else { - false - }; - param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); - - expected_arg_tys = vec![]; - self.err_args(supplied_arg_count) - }; - - debug!( - "check_argument_types: formal_tys={:?}", - formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>() - ); - - // If there is no expectation, expect formal_tys. - let expected_arg_tys = - if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() }; - - let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![]; - - // Check the arguments. - // We do this in a pretty awful way: first we type-check any arguments - // that are not closures, then we type-check the closures. This is so - // that we have more information about the types of arguments when we - // type-check the functions. This isn't really the right way to do this. - for &check_closures in &[false, true] { - debug!("check_closures={}", check_closures); - - // More awful hacks: before we check argument types, try to do - // an "opportunistic" trait resolution of any trait bounds on - // the call. This helps coercions. - if check_closures { - self.select_obligations_where_possible(false, |errors| { - self.point_at_type_arg_instead_of_call_if_possible(errors, expr); - self.point_at_arg_instead_of_call_if_possible( - errors, - &final_arg_types[..], - sp, - &args, - ); - }) - } - - // For C-variadic functions, we don't have a declared type for all of - // the arguments hence we only do our usual type checking with - // the arguments who's types we do know. - let t = if c_variadic { - expected_arg_count - } else if tuple_arguments == TupleArguments { - args.len() - } else { - supplied_arg_count - }; - for (i, arg) in args.iter().take(t).enumerate() { - // Warn only for the first loop (the "no closures" one). - // Closure arguments themselves can't be diverging, but - // a previous argument can, e.g., `foo(panic!(), || {})`. - if !check_closures { - self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); - } - - let is_closure = match arg.kind { - ExprKind::Closure(..) => true, - _ => false, - }; - - if is_closure != check_closures { - continue; - } - - debug!("checking the argument"); - let formal_ty = formal_tys[i]; - - // The special-cased logic below has three functions: - // 1. Provide as good of an expected type as possible. - let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]); - - let checked_ty = self.check_expr_with_expectation(&arg, expected); - - // 2. Coerce to the most detailed type that could be coerced - // to, which is `expected_ty` if `rvalue_hint` returns an - // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. - let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); - // We're processing function arguments so we definitely want to use - // two-phase borrows. - self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); - final_arg_types.push((i, checked_ty, coerce_ty)); - - // 3. Relate the expected type and the formal one, - // if the expected type was used for the coercion. - self.demand_suptype(arg.span, formal_ty, coerce_ty); - } - } - - // We also need to make sure we at least write the ty of the other - // arguments which we skipped above. - if c_variadic { - fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) { - use crate::structured_errors::{StructuredDiagnostic, VariadicError}; - VariadicError::new(s, span, t, cast_ty).diagnostic().emit(); - } - - for arg in args.iter().skip(expected_arg_count) { - let arg_ty = self.check_expr(&arg); - - // There are a few types which get autopromoted when passed via varargs - // in C but we just error out instead and require explicit casts. - let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); - match arg_ty.kind() { - ty::Float(ast::FloatTy::F32) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); - } - ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); - } - ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => { - variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); - } - ty::FnDef(..) => { - let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); - let ptr_ty = self.resolve_vars_if_possible(&ptr_ty); - variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); - } - _ => {} - } - } - } - } - - pub(super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> { - vec![self.tcx.ty_error(); len] - } - - /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk - /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s - /// reference a type argument. The reason to walk also the checked type is that the coerced type - /// can be not easily comparable with predicate type (because of coercion). If the types match - /// for either checked or coerced type, and there's only *one* argument that does, we point at - /// the corresponding argument's expression span instead of the `fn` call path span. - fn point_at_arg_instead_of_call_if_possible( - &self, - errors: &mut Vec<traits::FulfillmentError<'tcx>>, - final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)], - call_sp: Span, - args: &'tcx [hir::Expr<'tcx>], - ) { - // We *do not* do this for desugared call spans to keep good diagnostics when involving - // the `?` operator. - if call_sp.desugaring_kind().is_some() { - return; - } - - for error in errors { - // Only if the cause is somewhere inside the expression we want try to point at arg. - // Otherwise, it means that the cause is somewhere else and we should not change - // anything because we can break the correct span. - if !call_sp.contains(error.obligation.cause.span) { - continue; - } - - if let ty::PredicateAtom::Trait(predicate, _) = - error.obligation.predicate.skip_binders() - { - // Collect the argument position for all arguments that could have caused this - // `FulfillmentError`. - let mut referenced_in = final_arg_types - .iter() - .map(|&(i, checked_ty, _)| (i, checked_ty)) - .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) - .flat_map(|(i, ty)| { - let ty = self.resolve_vars_if_possible(&ty); - // We walk the argument type because the argument's type could have - // been `Option<T>`, but the `FulfillmentError` references `T`. - if ty.walk().any(|arg| arg == predicate.self_ty().into()) { - Some(i) - } else { - None - } - }) - .collect::<Vec<usize>>(); - - // Both checked and coerced types could have matched, thus we need to remove - // duplicates. - - // We sort primitive type usize here and can use unstable sort - referenced_in.sort_unstable(); - referenced_in.dedup(); - - if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { - // We make sure that only *one* argument matches the obligation failure - // and we assign the obligation's span to its expression's. - error.obligation.cause.make_mut().span = args[ref_in].span; - error.points_at_arg_span = true; - } - } - } - } - - /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the - /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s - /// were caused by them. If they were, we point at the corresponding type argument's span - /// instead of the `fn` call path span. - fn point_at_type_arg_instead_of_call_if_possible( - &self, - errors: &mut Vec<traits::FulfillmentError<'tcx>>, - call_expr: &'tcx hir::Expr<'tcx>, - ) { - if let hir::ExprKind::Call(path, _) = &call_expr.kind { - if let hir::ExprKind::Path(qpath) = &path.kind { - if let hir::QPath::Resolved(_, path) = &qpath { - for error in errors { - if let ty::PredicateAtom::Trait(predicate, _) = - error.obligation.predicate.skip_binders() - { - // If any of the type arguments in this path segment caused the - // `FullfillmentError`, point at its span (#61860). - for arg in path - .segments - .iter() - .filter_map(|seg| seg.args.as_ref()) - .flat_map(|a| a.args.iter()) - { - if let hir::GenericArg::Type(hir_ty) = &arg { - if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) = - &hir_ty.kind - { - // Avoid ICE with associated types. As this is best - // effort only, it's ok to ignore the case. It - // would trigger in `is_send::<T::AssocType>();` - // from `typeck-default-trait-impl-assoc-type.rs`. - } else { - let ty = AstConv::ast_ty_to_ty(self, hir_ty); - let ty = self.resolve_vars_if_possible(&ty); - if ty == predicate.self_ty() { - error.obligation.cause.make_mut().span = hir_ty.span; - } - } - } - } - } - } - } - } - } - } - - // AST fragment checking - pub(super) fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { - let tcx = self.tcx; - - match lit.node { - ast::LitKind::Str(..) => tcx.mk_static_str(), - ast::LitKind::ByteStr(ref v) => { - tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) - } - ast::LitKind::Byte(_) => tcx.types.u8, - ast::LitKind::Char(_) => tcx.types.char, - ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), - ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), - ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { - ty::Int(_) | ty::Uint(_) => Some(ty), - ty::Char => Some(tcx.types.u8), - ty::RawPtr(..) => Some(tcx.types.usize), - ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize), - _ => None, - }); - opt_ty.unwrap_or_else(|| self.next_int_var()) - } - ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t), - ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { - ty::Float(_) => Some(ty), - _ => None, - }); - opt_ty.unwrap_or_else(|| self.next_float_var()) - } - ast::LitKind::Bool(_) => tcx.types.bool, - ast::LitKind::Err(_) => tcx.ty_error(), - } - } - - /// Unifies the output type with the expected type early, for more coercions - /// and forward type information on the input expressions. - pub(super) fn expected_inputs_for_expected_output( - &self, - call_span: Span, - expected_ret: Expectation<'tcx>, - formal_ret: Ty<'tcx>, - formal_args: &[Ty<'tcx>], - ) -> Vec<Ty<'tcx>> { - let formal_ret = self.resolve_vars_with_obligations(formal_ret); - let ret_ty = match expected_ret.only_has_type(self) { - Some(ret) => ret, - None => return Vec::new(), - }; - let expect_args = self - .fudge_inference_if_ok(|| { - // Attempt to apply a subtyping relationship between the formal - // return type (likely containing type variables if the function - // is polymorphic) and the expected return type. - // No argument expectations are produced if unification fails. - let origin = self.misc(call_span); - let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); - - // FIXME(#27336) can't use ? here, Try::from_error doesn't default - // to identity so the resulting type is not constrained. - match ures { - Ok(ok) => { - // Process any obligations locally as much as - // we can. We don't care if some things turn - // out unconstrained or ambiguous, as we're - // just trying to get hints here. - self.save_and_restore_in_snapshot_flag(|_| { - let mut fulfill = TraitEngine::new(self.tcx); - for obligation in ok.obligations { - fulfill.register_predicate_obligation(self, obligation); - } - fulfill.select_where_possible(self) - }) - .map_err(|_| ())?; - } - Err(_) => return Err(()), - } - - // Record all the argument types, with the substitutions - // produced from the above subtyping unification. - Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect()) - }) - .unwrap_or_default(); - debug!( - "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", - formal_args, formal_ret, expect_args, expected_ret - ); - expect_args - } - - pub fn check_struct_path( - &self, - qpath: &QPath<'_>, - hir_id: hir::HirId, - ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { - let path_span = qpath.qself_span(); - let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); - let variant = match def { - Res::Err => { - self.set_tainted_by_errors(); - return None; - } - Res::Def(DefKind::Variant, _) => match ty.kind() { - ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)), - _ => bug!("unexpected type: {:?}", ty), - }, - Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) - | Res::SelfTy(..) => match ty.kind() { - ty::Adt(adt, substs) if !adt.is_enum() => { - Some((adt.non_enum_variant(), adt.did, substs)) - } - _ => None, - }, - _ => bug!("unexpected definition: {:?}", def), - }; - - if let Some((variant, did, substs)) = variant { - debug!("check_struct_path: did={:?} substs={:?}", did, substs); - self.write_user_type_annotation_from_substs(hir_id, did, substs, None); - - // Check bounds on type arguments used in the path. - let (bounds, _) = self.instantiate_bounds(path_span, did, substs); - let cause = - traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did)); - self.add_obligations_for_parameters(cause, bounds); - - Some((variant, ty)) - } else { - struct_span_err!( - self.tcx.sess, - path_span, - E0071, - "expected struct, variant or union type, found {}", - ty.sort_string(self.tcx) - ) - .span_label(path_span, "not a struct") - .emit(); - None - } - } - - // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. - // The newly resolved definition is written into `type_dependent_defs`. - fn finish_resolving_struct_path( - &self, - qpath: &QPath<'_>, - path_span: Span, - hir_id: hir::HirId, - ) -> (Res, Ty<'tcx>) { - match *qpath { - QPath::Resolved(ref maybe_qself, ref path) => { - let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); - let ty = AstConv::res_to_ty(self, self_ty, path, true); - (path.res, ty) - } - QPath::TypeRelative(ref qself, ref segment) => { - let ty = self.to_ty(qself); - - let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind { - path.res - } else { - Res::Err - }; - let result = - AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); - let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); - let result = result.map(|(_, kind, def_id)| (kind, def_id)); - - // Write back the new resolution. - self.write_resolution(hir_id, result); - - (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) - } - QPath::LangItem(lang_item, span) => { - self.resolve_lang_item_path(lang_item, span, hir_id) - } - } - } - - pub(super) fn resolve_lang_item_path( - &self, - lang_item: hir::LangItem, - span: Span, - hir_id: hir::HirId, - ) -> (Res, Ty<'tcx>) { - let def_id = self.tcx.require_lang_item(lang_item, Some(span)); - let def_kind = self.tcx.def_kind(def_id); - - let item_ty = if let DefKind::Variant = def_kind { - self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent")) - } else { - self.tcx.type_of(def_id) - }; - let substs = self.infcx.fresh_substs_for_item(span, def_id); - let ty = item_ty.subst(self.tcx, substs); - - self.write_resolution(hir_id, Ok((def_kind, def_id))); - self.add_required_obligations(span, def_id, &substs); - (Res::Def(def_kind, def_id), ty) - } - - /// Resolves an associated value path into a base type and associated constant, or method - /// resolution. The newly resolved definition is written into `type_dependent_defs`. - pub fn resolve_ty_and_res_ufcs<'b>( - &self, - qpath: &'b QPath<'b>, - hir_id: hir::HirId, - span: Span, - ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) { - debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span); - let (ty, qself, item_segment) = match *qpath { - QPath::Resolved(ref opt_qself, ref path) => { - return ( - path.res, - opt_qself.as_ref().map(|qself| self.to_ty(qself)), - &path.segments[..], - ); - } - QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), - QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"), - }; - if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) - { - // Return directly on cache hit. This is useful to avoid doubly reporting - // errors with default match binding modes. See #44614. - let def = - cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err); - return (def, Some(ty), slice::from_ref(&**item_segment)); - } - let item_name = item_segment.ident; - let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| { - let result = match error { - method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), - _ => Err(ErrorReported), - }; - if item_name.name != kw::Invalid { - if let Some(mut e) = self.report_method_error( - span, - ty, - item_name, - SelfSource::QPath(qself), - error, - None, - ) { - e.emit(); - } - } - result - }); - - // Write back the new resolution. - self.write_resolution(hir_id, result); - ( - result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), - Some(ty), - slice::from_ref(&**item_segment), - ) - } - - pub fn check_decl_initializer( - &self, - local: &'tcx hir::Local<'tcx>, - init: &'tcx hir::Expr<'tcx>, - ) -> Ty<'tcx> { - // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed - // for #42640 (default match binding modes). - // - // See #44848. - let ref_bindings = local.pat.contains_explicit_ref_binding(); - - let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty; - if let Some(m) = ref_bindings { - // Somewhat subtle: if we have a `ref` binding in the pattern, - // we want to avoid introducing coercions for the RHS. This is - // both because it helps preserve sanity and, in the case of - // ref mut, for soundness (issue #23116). In particular, in - // the latter case, we need to be clear that the type of the - // referent for the reference that results is *equal to* the - // type of the place it is referencing, and not some - // supertype thereof. - let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); - self.demand_eqtype(init.span, local_ty, init_ty); - init_ty - } else { - self.check_expr_coercable_to_type(init, local_ty, None) - } - } - - /// Type check a `let` statement. - pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { - // Determine and write the type which we'll check the pattern against. - let ty = self.local_ty(local.span, local.hir_id).decl_ty; - self.write_ty(local.hir_id, ty); - - // Type check the initializer. - if let Some(ref init) = local.init { - let init_ty = self.check_decl_initializer(local, &init); - self.overwrite_local_ty_if_err(local, ty, init_ty); - } - - // Does the expected pattern type originate from an expression and what is the span? - let (origin_expr, ty_span) = match (local.ty, local.init) { - (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type. - (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee. - _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained. - }; - - // Type check the pattern. Override if necessary to avoid knock-on errors. - self.check_pat_top(&local.pat, ty, ty_span, origin_expr); - let pat_ty = self.node_ty(local.pat.hir_id); - self.overwrite_local_ty_if_err(local, ty, pat_ty); - } - - fn overwrite_local_ty_if_err( - &self, - local: &'tcx hir::Local<'tcx>, - decl_ty: Ty<'tcx>, - ty: Ty<'tcx>, - ) { - if ty.references_error() { - // Override the types everywhere with `err()` to avoid knock on errors. - self.write_ty(local.hir_id, ty); - self.write_ty(local.pat.hir_id, ty); - let local_ty = LocalTy { decl_ty, revealed_ty: ty }; - self.locals.borrow_mut().insert(local.hir_id, local_ty); - self.locals.borrow_mut().insert(local.pat.hir_id, local_ty); - } - } - - pub(super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) { - err.span_suggestion_short( - span.shrink_to_hi(), - "consider using a semicolon here", - ";".to_string(), - Applicability::MachineApplicable, - ); - } - - pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { - // Don't do all the complex logic below for `DeclItem`. - match stmt.kind { - hir::StmtKind::Item(..) => return, - hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} - } - - self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); - - // Hide the outer diverging and `has_errors` flags. - let old_diverges = self.diverges.replace(Diverges::Maybe); - let old_has_errors = self.has_errors.replace(false); - - match stmt.kind { - hir::StmtKind::Local(ref l) => { - self.check_decl_local(&l); - } - // Ignore for now. - hir::StmtKind::Item(_) => {} - hir::StmtKind::Expr(ref expr) => { - // Check with expected type of `()`. - self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { - self.suggest_semicolon_at_end(expr.span, err); - }); - } - hir::StmtKind::Semi(ref expr) => { - self.check_expr(&expr); - } - } - - // Combine the diverging and `has_error` flags. - self.diverges.set(self.diverges.get() | old_diverges); - self.has_errors.set(self.has_errors.get() | old_has_errors); - } - - pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { - let unit = self.tcx.mk_unit(); - let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); - - // if the block produces a `!` value, that can always be - // (effectively) coerced to unit. - if !ty.is_never() { - self.demand_suptype(blk.span, unit, ty); - } - } - - /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail - /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors - /// when given code like the following: - /// ```text - /// if false { return 0i32; } else { 1u32 } - /// // ^^^^ point at this instead of the whole `if` expression - /// ``` - fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { - if let hir::ExprKind::Match(_, arms, _) = &expr.kind { - let arm_spans: Vec<Span> = arms - .iter() - .filter_map(|arm| { - self.in_progress_typeck_results - .and_then(|typeck_results| { - typeck_results.borrow().node_type_opt(arm.body.hir_id) - }) - .and_then(|arm_ty| { - if arm_ty.is_never() { - None - } else { - Some(match &arm.body.kind { - // Point at the tail expression when possible. - hir::ExprKind::Block(block, _) => { - block.expr.as_ref().map(|e| e.span).unwrap_or(block.span) - } - _ => arm.body.span, - }) - } - }) - }) - .collect(); - if arm_spans.len() == 1 { - return arm_spans[0]; - } - } - expr.span - } - - pub(super) fn check_block_with_expected( - &self, - blk: &'tcx hir::Block<'tcx>, - expected: Expectation<'tcx>, - ) -> Ty<'tcx> { - let prev = { - let mut fcx_ps = self.ps.borrow_mut(); - let unsafety_state = fcx_ps.recurse(blk); - replace(&mut *fcx_ps, unsafety_state) - }; - - // In some cases, blocks have just one exit, but other blocks - // can be targeted by multiple breaks. This can happen both - // with labeled blocks as well as when we desugar - // a `try { ... }` expression. - // - // Example 1: - // - // 'a: { if true { break 'a Err(()); } Ok(()) } - // - // Here we would wind up with two coercions, one from - // `Err(())` and the other from the tail expression - // `Ok(())`. If the tail expression is omitted, that's a - // "forced unit" -- unless the block diverges, in which - // case we can ignore the tail expression (e.g., `'a: { - // break 'a 22; }` would not force the type of the block - // to be `()`). - let tail_expr = blk.expr.as_ref(); - let coerce_to_ty = expected.coercion_target_type(self, blk.span); - let coerce = if blk.targeted_by_break { - CoerceMany::new(coerce_to_ty) - } else { - let tail_expr: &[&hir::Expr<'_>] = match tail_expr { - Some(e) => slice::from_ref(e), - None => &[], - }; - CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) - }; - - let prev_diverges = self.diverges.get(); - let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; - - let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { - for s in blk.stmts { - self.check_stmt(s); - } - - // check the tail expression **without** holding the - // `enclosing_breakables` lock below. - let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); - - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - let ctxt = enclosing_breakables.find_breakable(blk.hir_id); - let coerce = ctxt.coerce.as_mut().unwrap(); - if let Some(tail_expr_ty) = tail_expr_ty { - let tail_expr = tail_expr.unwrap(); - let span = self.get_expr_coercion_span(tail_expr); - let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); - coerce.coerce(self, &cause, tail_expr, tail_expr_ty); - } else { - // Subtle: if there is no explicit tail expression, - // that is typically equivalent to a tail expression - // of `()` -- except if the block diverges. In that - // case, there is no value supplied from the tail - // expression (assuming there are no other breaks, - // this implies that the type of the block will be - // `!`). - // - // #41425 -- label the implicit `()` as being the - // "found type" here, rather than the "expected type". - if !self.diverges.get().is_always() { - // #50009 -- Do not point at the entire fn block span, point at the return type - // span, as it is the cause of the requirement, and - // `consider_hint_about_removing_semicolon` will point at the last expression - // if it were a relevant part of the error. This improves usability in editors - // that highlight errors inline. - let mut sp = blk.span; - let mut fn_span = None; - if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { - let ret_sp = decl.output.span(); - if let Some(block_sp) = self.parent_item_span(blk.hir_id) { - // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the - // output would otherwise be incorrect and even misleading. Make sure - // the span we're aiming at correspond to a `fn` body. - if block_sp == blk.span { - sp = ret_sp; - fn_span = Some(ident.span); - } - } - } - coerce.coerce_forced_unit( - self, - &self.misc(sp), - &mut |err| { - if let Some(expected_ty) = expected.only_has_type(self) { - self.consider_hint_about_removing_semicolon(blk, expected_ty, err); - } - if let Some(fn_span) = fn_span { - err.span_label( - fn_span, - "implicitly returns `()` as its body has no tail or `return` \ - expression", - ); - } - }, - false, - ); - } - } - }); - - if ctxt.may_break { - // If we can break from the block, then the block's exit is always reachable - // (... as long as the entry is reachable) - regardless of the tail of the block. - self.diverges.set(prev_diverges); - } - - let mut ty = ctxt.coerce.unwrap().complete(self); - - if self.has_errors.get() || ty.references_error() { - ty = self.tcx.ty_error() - } - - self.write_ty(blk.hir_id, ty); - - *self.ps.borrow_mut() = prev; - ty - } - - fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { - let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id)); - match node { - Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) - | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { - let body = self.tcx.hir().body(body_id); - if let ExprKind::Block(block, _) = &body.value.kind { - return Some(block.span); - } - } - _ => {} - } - None - } - - /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. - fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { - let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id)); - self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) - } - - /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. - pub(super) fn get_node_fn_decl( - &self, - node: Node<'tcx>, - ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { - match node { - Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { - // This is less than ideal, it will not suggest a return type span on any - // method called `main`, regardless of whether it is actually the entry point, - // but it will still present it as the reason for the expected type. - Some((&sig.decl, ident, ident.name != sym::main)) - } - Node::TraitItem(&hir::TraitItem { - ident, - kind: hir::TraitItemKind::Fn(ref sig, ..), - .. - }) => Some((&sig.decl, ident, true)), - Node::ImplItem(&hir::ImplItem { - ident, - kind: hir::ImplItemKind::Fn(ref sig, ..), - .. - }) => Some((&sig.decl, ident, false)), - _ => None, - } - } - - /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a - /// suggestion can be made, `None` otherwise. - pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> { - // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or - // `while` before reaching it, as block tail returns are not available in them. - self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { - let parent = self.tcx.hir().get(blk_id); - self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) - }) - } - - /// On implicit return expressions with mismatched types, provides the following suggestions: - /// - /// - Points out the method's return type as the reason for the expected type. - /// - Possible missing semicolon. - /// - Possible missing return type if the return type is the default, and not `fn main()`. - pub fn suggest_mismatched_types_on_tail( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &'tcx hir::Expr<'tcx>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - cause_span: Span, - blk_id: hir::HirId, - ) -> bool { - let expr = expr.peel_drop_temps(); - self.suggest_missing_semicolon(err, expr, expected, cause_span); - let mut pointing_at_return_type = false; - if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { - pointing_at_return_type = - self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest); - } - pointing_at_return_type - } - - /// When encountering an fn-like ctor that needs to unify with a value, check whether calling - /// the ctor would successfully solve the type mismatch and if so, suggest it: - /// ``` - /// fn foo(x: usize) -> usize { x } - /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)` - /// ``` - fn suggest_fn_call( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) -> bool { - let hir = self.tcx.hir(); - let (def_id, sig) = match *found.kind() { - ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), - ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()), - _ => return false, - }; - - let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0; - let sig = self.normalize_associated_types_in(expr.span, &sig); - if self.can_coerce(sig.output(), expected) { - let (mut sugg_call, applicability) = if sig.inputs().is_empty() { - (String::new(), Applicability::MachineApplicable) - } else { - ("...".to_string(), Applicability::HasPlaceholders) - }; - let mut msg = "call this function"; - match hir.get_if_local(def_id) { - Some( - Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. }) - | Node::ImplItem(hir::ImplItem { - kind: hir::ImplItemKind::Fn(_, body_id), .. - }) - | Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)), - .. - }), - ) => { - let body = hir.body(*body_id); - sugg_call = body - .params - .iter() - .map(|param| match ¶m.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => - { - ident.to_string() - } - _ => "_".to_string(), - }) - .collect::<Vec<_>>() - .join(", "); - } - Some(Node::Expr(hir::Expr { - kind: ExprKind::Closure(_, _, body_id, _, _), - span: full_closure_span, - .. - })) => { - if *full_closure_span == expr.span { - return false; - } - msg = "call this closure"; - let body = hir.body(*body_id); - sugg_call = body - .params - .iter() - .map(|param| match ¶m.pat.kind { - hir::PatKind::Binding(_, _, ident, None) - if ident.name != kw::SelfLower => - { - ident.to_string() - } - _ => "_".to_string(), - }) - .collect::<Vec<_>>() - .join(", "); - } - Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { - sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", "); - match def_id.as_local().map(|def_id| hir.def_kind(def_id)) { - Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { - msg = "instantiate this tuple variant"; - } - Some(DefKind::Ctor(CtorOf::Struct, _)) => { - msg = "instantiate this tuple struct"; - } - _ => {} - } - } - Some(Node::ForeignItem(hir::ForeignItem { - kind: hir::ForeignItemKind::Fn(_, idents, _), - .. - })) => { - sugg_call = idents - .iter() - .map(|ident| { - if ident.name != kw::SelfLower { - ident.to_string() - } else { - "_".to_string() - } - }) - .collect::<Vec<_>>() - .join(", ") - } - Some(Node::TraitItem(hir::TraitItem { - kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)), - .. - })) => { - sugg_call = idents - .iter() - .map(|ident| { - if ident.name != kw::SelfLower { - ident.to_string() - } else { - "_".to_string() - } - }) - .collect::<Vec<_>>() - .join(", ") - } - _ => {} - } - err.span_suggestion_verbose( - expr.span.shrink_to_hi(), - &format!("use parentheses to {}", msg), - format!("({})", sugg_call), - applicability, - ); - return true; - } - false - } - - pub fn suggest_deref_ref_or_into( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, - ) { - if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { - err.span_suggestion(sp, msg, suggestion, applicability); - } else if let (ty::FnDef(def_id, ..), true) = - (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) - { - if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { - let sp = self.sess().source_map().guess_head_span(sp); - err.span_label(sp, &format!("{} defined here", found)); - } - } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { - let is_struct_pat_shorthand_field = - self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span); - let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); - if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { - let mut suggestions = iter::repeat(&expr_text) - .zip(methods.iter()) - .filter_map(|(receiver, method)| { - let method_call = format!(".{}()", method.ident); - if receiver.ends_with(&method_call) { - None // do not suggest code that is already there (#53348) - } else { - let method_call_list = [".to_vec()", ".to_string()"]; - let sugg = if receiver.ends_with(".clone()") - && method_call_list.contains(&method_call.as_str()) - { - let max_len = receiver.rfind('.').unwrap(); - format!("{}{}", &receiver[..max_len], method_call) - } else { - if expr.precedence().order() < ExprPrecedence::MethodCall.order() { - format!("({}){}", receiver, method_call) - } else { - format!("{}{}", receiver, method_call) - } - }; - Some(if is_struct_pat_shorthand_field { - format!("{}: {}", receiver, sugg) - } else { - sugg - }) - } - }) - .peekable(); - if suggestions.peek().is_some() { - err.span_suggestions( - expr.span, - "try using a conversion method", - suggestions, - Applicability::MaybeIncorrect, - ); - } - } - } - } - - /// When encountering the expected boxed value allocated in the stack, suggest allocating it - /// in the heap by calling `Box::new()`. - pub(super) fn suggest_boxing_when_appropriate( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - if self.tcx.hir().is_inside_const_context(expr.hir_id) { - // Do not suggest `Box::new` in const context. - return; - } - if !expected.is_box() || found.is_box() { - return; - } - let boxed_found = self.tcx.mk_box(found); - if let (true, Ok(snippet)) = ( - self.can_coerce(boxed_found, expected), - self.sess().source_map().span_to_snippet(expr.span), - ) { - err.span_suggestion( - expr.span, - "store this in the heap by calling `Box::new`", - format!("Box::new({})", snippet), - Applicability::MachineApplicable, - ); - err.note( - "for more on the distinction between the stack and the heap, read \ - https://doc.rust-lang.org/book/ch15-01-box.html, \ - https://doc.rust-lang.org/rust-by-example/std/box.html, and \ - https://doc.rust-lang.org/std/boxed/index.html", - ); - } - } - - pub(super) fn note_internal_mutation_in_method( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - if found != self.tcx.types.unit { - return; - } - if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind { - if self - .typeck_results - .borrow() - .expr_ty_adjusted_opt(rcvr) - .map_or(true, |ty| expected.peel_refs() != ty.peel_refs()) - { - return; - } - let mut sp = MultiSpan::from_span(path_segment.ident.span); - sp.push_span_label( - path_segment.ident.span, - format!( - "this call modifies {} in-place", - match rcvr.kind { - ExprKind::Path(QPath::Resolved( - None, - hir::Path { segments: [segment], .. }, - )) => format!("`{}`", segment.ident), - _ => "its receiver".to_string(), - } - ), - ); - sp.push_span_label( - rcvr.span, - "you probably want to use this value after calling the method...".to_string(), - ); - err.span_note( - sp, - &format!("method `{}` modifies its receiver in-place", path_segment.ident), - ); - err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); - } - } - - /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. - pub(super) fn suggest_calling_boxed_future_when_appropriate( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) -> bool { - // Handle #68197. - - if self.tcx.hir().is_inside_const_context(expr.hir_id) { - // Do not suggest `Box::new` in const context. - return false; - } - let pin_did = self.tcx.lang_items().pin_type(); - match expected.kind() { - ty::Adt(def, _) if Some(def.did) != pin_did => return false, - // This guards the `unwrap` and `mk_box` below. - _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, - _ => {} - } - let boxed_found = self.tcx.mk_box(found); - let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap(); - if let (true, Ok(snippet)) = ( - self.can_coerce(new_found, expected), - self.sess().source_map().span_to_snippet(expr.span), - ) { - match found.kind() { - ty::Adt(def, _) if def.is_box() => { - err.help("use `Box::pin`"); - } - _ => { - err.span_suggestion( - expr.span, - "you need to pin and box this expression", - format!("Box::pin({})", snippet), - Applicability::MachineApplicable, - ); - } - } - true - } else { - false - } - } - - /// A common error is to forget to add a semicolon at the end of a block, e.g., - /// - /// ``` - /// fn foo() { - /// bar_that_returns_u32() - /// } - /// ``` - /// - /// This routine checks if the return expression in a block would make sense on its own as a - /// statement and the return type has been left as default or has been specified as `()`. If so, - /// it suggests adding a semicolon. - fn suggest_missing_semicolon( - &self, - err: &mut DiagnosticBuilder<'_>, - expression: &'tcx hir::Expr<'tcx>, - expected: Ty<'tcx>, - cause_span: Span, - ) { - if expected.is_unit() { - // `BlockTailExpression` only relevant if the tail expr would be - // useful on its own. - match expression.kind { - ExprKind::Call(..) - | ExprKind::MethodCall(..) - | ExprKind::Loop(..) - | ExprKind::Match(..) - | ExprKind::Block(..) => { - err.span_suggestion( - cause_span.shrink_to_hi(), - "try adding a semicolon", - ";".to_string(), - Applicability::MachineApplicable, - ); - } - _ => (), - } - } - } - - /// A possible error is to forget to add a return type that is needed: - /// - /// ``` - /// fn foo() { - /// bar_that_returns_u32() - /// } - /// ``` - /// - /// This routine checks if the return type is left as default, the method is not part of an - /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return - /// type. - pub(super) fn suggest_missing_return_type( - &self, - err: &mut DiagnosticBuilder<'_>, - fn_decl: &hir::FnDecl<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - can_suggest: bool, - ) -> bool { - // Only suggest changing the return type for methods that - // haven't set a return type at all (and aren't `fn main()` or an impl). - match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) { - (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { - err.span_suggestion( - span, - "try adding a return type", - format!("-> {} ", self.resolve_vars_with_obligations(found)), - Applicability::MachineApplicable, - ); - true - } - (&hir::FnRetTy::DefaultReturn(span), false, true, true) => { - err.span_label(span, "possibly return type missing here?"); - true - } - (&hir::FnRetTy::DefaultReturn(span), _, false, true) => { - // `fn main()` must return `()`, do not suggest changing return type - err.span_label(span, "expected `()` because of default return type"); - true - } - // expectation was caused by something else, not the default return - (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false, - (&hir::FnRetTy::Return(ref ty), _, _, _) => { - // Only point to return type if the expected type is the return type, as if they - // are not, the expectation must have been caused by something else. - debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind); - let sp = ty.span; - let ty = AstConv::ast_ty_to_ty(self, ty); - debug!("suggest_missing_return_type: return type {:?}", ty); - debug!("suggest_missing_return_type: expected type {:?}", ty); - if ty.kind() == expected.kind() { - err.span_label(sp, format!("expected `{}` because of return type", expected)); - return true; - } - false - } - } - } - - /// A possible error is to forget to add `.await` when using futures: - /// - /// ``` - /// async fn make_u32() -> u32 { - /// 22 - /// } - /// - /// fn take_u32(x: u32) {} - /// - /// async fn foo() { - /// let x = make_u32(); - /// take_u32(x); - /// } - /// ``` - /// - /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the - /// expected type. If this is the case, and we are inside of an async body, it suggests adding - /// `.await` to the tail of the expression. - pub(super) fn suggest_missing_await( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found); - // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the - // body isn't `async`. - let item_id = self.tcx().hir().get_parent_node(self.body_id); - if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) { - let body = self.tcx().hir().body(body_id); - if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { - let sp = expr.span; - // Check for `Future` implementations by constructing a predicate to - // prove: `<T as Future>::Output == U` - let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp)); - let item_def_id = self - .tcx - .associated_items(future_trait) - .in_definition_order() - .next() - .unwrap() - .def_id; - // `<T as Future>::Output` - let projection_ty = ty::ProjectionTy { - // `T` - substs: self - .tcx - .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)), - // `Future::Output` - item_def_id, - }; - - let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate { - projection_ty, - ty: expected, - }) - .potentially_quantified(self.tcx, ty::PredicateKind::ForAll); - let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); - - debug!("suggest_missing_await: trying obligation {:?}", obligation); - - if self.infcx.predicate_may_hold(&obligation) { - debug!("suggest_missing_await: obligation held: {:?}", obligation); - if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { - err.span_suggestion( - sp, - "consider using `.await` here", - format!("{}.await", code), - Applicability::MaybeIncorrect, - ); - } else { - debug!("suggest_missing_await: no snippet for {:?}", sp); - } - } else { - debug!("suggest_missing_await: obligation did not hold: {:?}", obligation) - } - } - } - } - - pub(super) fn suggest_missing_parentheses( - &self, - err: &mut DiagnosticBuilder<'_>, - expr: &hir::Expr<'_>, - ) { - let sp = self.tcx.sess.source_map().start_point(expr.span); - if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { - // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` - self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None); - } - } - - pub(super) fn note_need_for_fn_pointer( - &self, - err: &mut DiagnosticBuilder<'_>, - expected: Ty<'tcx>, - found: Ty<'tcx>, - ) { - let (sig, did, substs) = match (&expected.kind(), &found.kind()) { - (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { - let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); - let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); - if sig1 != sig2 { - return; - } - err.note( - "different `fn` items always have unique types, even if their signatures are \ - the same", - ); - (sig1, *did1, substs1) - } - (ty::FnDef(did, substs), ty::FnPtr(sig2)) => { - let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs); - if sig1 != *sig2 { - return; - } - (sig1, *did, substs) - } - _ => return, - }; - err.help(&format!("change the expected type to be function pointer `{}`", sig)); - err.help(&format!( - "if the expected type is due to type inference, cast the expected `fn` to a function \ - pointer: `{} as {}`", - self.tcx.def_path_str_with_substs(did, substs), - sig - )); - } - - /// A common error is to add an extra semicolon: - /// - /// ``` - /// fn foo() -> usize { - /// 22; - /// } - /// ``` - /// - /// This routine checks if the final statement in a block is an - /// expression with an explicit semicolon whose type is compatible - /// with `expected_ty`. If so, it suggests removing the semicolon. - fn consider_hint_about_removing_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - err: &mut DiagnosticBuilder<'_>, - ) { - if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) { - err.span_suggestion( - span_semi, - "consider removing this semicolon", - String::new(), - Applicability::MachineApplicable, - ); - } - } - - pub(super) fn could_remove_semicolon( - &self, - blk: &'tcx hir::Block<'tcx>, - expected_ty: Ty<'tcx>, - ) -> Option<Span> { - // Be helpful when the user wrote `{... expr;}` and - // taking the `;` off is enough to fix the error. - let last_stmt = blk.stmts.last()?; - let last_expr = match last_stmt.kind { - hir::StmtKind::Semi(ref e) => e, - _ => return None, - }; - let last_expr_ty = self.node_ty(last_expr.hir_id); - if matches!(last_expr_ty.kind(), ty::Error(_)) - || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() - { - return None; - } - let original_span = original_sp(last_stmt.span, blk.span); - Some(original_span.with_lo(original_span.hi() - BytePos(1))) - } - - // Instantiates the given path, which must refer to an item with the given - // number of type parameters and type. - pub fn instantiate_value_path( - &self, - segments: &[hir::PathSegment<'_>], - self_ty: Option<Ty<'tcx>>, - res: Res, - span: Span, - hir_id: hir::HirId, - ) -> (Ty<'tcx>, Res) { - debug!( - "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", - segments, self_ty, res, hir_id, - ); - - let tcx = self.tcx; - - let path_segs = match res { - Res::Local(_) | Res::SelfCtor(_) => vec![], - Res::Def(kind, def_id) => { - AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id) - } - _ => bug!("instantiate_value_path on {:?}", res), - }; - - let mut user_self_ty = None; - let mut is_alias_variant_ctor = false; - match res { - Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => { - if let Some(self_ty) = self_ty { - let adt_def = self_ty.ty_adt_def().unwrap(); - user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty }); - is_alias_variant_ctor = true; - } - } - Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { - let container = tcx.associated_item(def_id).container; - debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); - match container { - ty::TraitContainer(trait_did) => { - callee::check_legal_trait_for_method_call(tcx, span, None, trait_did) - } - ty::ImplContainer(impl_def_id) => { - if segments.len() == 1 { - // `<T>::assoc` will end up here, and so - // can `T::assoc`. It this came from an - // inherent impl, we need to record the - // `T` for posterity (see `UserSelfTy` for - // details). - let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); - user_self_ty = Some(UserSelfTy { impl_def_id, self_ty }); - } - } - } - } - _ => {} - } - - // Now that we have categorized what space the parameters for each - // segment belong to, let's sort out the parameters that the user - // provided (if any) into their appropriate spaces. We'll also report - // errors if type parameters are provided in an inappropriate place. - - let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); - let generics_has_err = AstConv::prohibit_generics( - self, - segments.iter().enumerate().filter_map(|(index, seg)| { - if !generic_segs.contains(&index) || is_alias_variant_ctor { - Some(seg) - } else { - None - } - }), - ); - - if let Res::Local(hid) = res { - let ty = self.local_ty(span, hid).decl_ty; - let ty = self.normalize_associated_types_in(span, &ty); - self.write_ty(hir_id, ty); - return (ty, res); - } - - if generics_has_err { - // Don't try to infer type parameters when prohibited generic arguments were given. - user_self_ty = None; - } - - // Now we have to compare the types that the user *actually* - // provided against the types that were *expected*. If the user - // did not provide any types, then we want to substitute inference - // variables. If the user provided some types, we may still need - // to add defaults. If the user provided *too many* types, that's - // a problem. - - let mut infer_args_for_err = FxHashSet::default(); - for &PathSeg(def_id, index) in &path_segs { - let seg = &segments[index]; - let generics = tcx.generics_of(def_id); - // Argument-position `impl Trait` is treated as a normal generic - // parameter internally, but we don't allow users to specify the - // parameter's value explicitly, so we have to do some error- - // checking here. - if let GenericArgCountResult { - correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }), - .. - } = AstConv::check_generic_arg_count_for_call( - tcx, span, &generics, &seg, false, // `is_method_call` - ) { - infer_args_for_err.insert(index); - self.set_tainted_by_errors(); // See issue #53251. - } - } - - let has_self = path_segs - .last() - .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self) - .unwrap_or(false); - - let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { - let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); - match *ty.kind() { - ty::Adt(adt_def, substs) if adt_def.has_ctor() => { - let variant = adt_def.non_enum_variant(); - let ctor_def_id = variant.ctor_def_id.unwrap(); - ( - Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id), - Some(substs), - ) - } - _ => { - let mut err = tcx.sess.struct_span_err( - span, - "the `Self` constructor can only be used with tuple or unit structs", - ); - if let Some(adt_def) = ty.ty_adt_def() { - match adt_def.adt_kind() { - AdtKind::Enum => { - err.help("did you mean to use one of the enum's variants?"); - } - AdtKind::Struct | AdtKind::Union => { - err.span_suggestion( - span, - "use curly brackets", - String::from("Self { /* fields */ }"), - Applicability::HasPlaceholders, - ); - } - } - } - err.emit(); - - return (tcx.ty_error(), res); - } - } - } else { - (res, None) - }; - let def_id = res.def_id(); - - // The things we are substituting into the type should not contain - // escaping late-bound regions, and nor should the base type scheme. - let ty = tcx.type_of(def_id); - - let arg_count = GenericArgCountResult { - explicit_late_bound: ExplicitLateBound::No, - correct: if infer_args_for_err.is_empty() { - Ok(()) - } else { - Err(GenericArgCountMismatch::default()) - }, - }; - - let substs = self_ctor_substs.unwrap_or_else(|| { - AstConv::create_substs_for_generic_args( - tcx, - def_id, - &[][..], - has_self, - self_ty, - arg_count, - // Provide the generic args, and whether types should be inferred. - |def_id| { - if let Some(&PathSeg(_, index)) = - path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) - { - // If we've encountered an `impl Trait`-related error, we're just - // going to infer the arguments for better error messages. - if !infer_args_for_err.contains(&index) { - // Check whether the user has provided generic arguments. - if let Some(ref data) = segments[index].args { - return (Some(data), segments[index].infer_args); - } - } - return (None, segments[index].infer_args); - } - - (None, true) - }, - // Provide substitutions for parameters for which (valid) arguments have been provided. - |param, arg| match (¶m.kind, arg) { - (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { - AstConv::ast_region_to_region(self, lt, Some(param)).into() - } - (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { - self.to_ty(ty).into() - } - (GenericParamDefKind::Const, GenericArg::Const(ct)) => { - self.const_arg_to_const(&ct.value, param.def_id).into() - } - _ => unreachable!(), - }, - // Provide substitutions for parameters for which arguments are inferred. - |substs, param, infer_args| { - match param.kind { - GenericParamDefKind::Lifetime => { - self.re_infer(Some(param), span).unwrap().into() - } - GenericParamDefKind::Type { has_default, .. } => { - if !infer_args && has_default { - // If we have a default, then we it doesn't matter that we're not - // inferring the type arguments: we provide the default where any - // is missing. - let default = tcx.type_of(param.def_id); - self.normalize_ty( - span, - default.subst_spanned(tcx, substs.unwrap(), Some(span)), - ) - .into() - } else { - // If no type arguments were provided, we have to infer them. - // This case also occurs as a result of some malformed input, e.g. - // a lifetime argument being given instead of a type parameter. - // Using inference instead of `Error` gives better error messages. - self.var_for_def(span, param) - } - } - GenericParamDefKind::Const => { - // FIXME(const_generics:defaults) - // No const parameters were provided, we have to infer them. - self.var_for_def(span, param) - } - } - }, - ) - }); - assert!(!substs.has_escaping_bound_vars()); - assert!(!ty.has_escaping_bound_vars()); - - // First, store the "user substs" for later. - self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty); - - self.add_required_obligations(span, def_id, &substs); - - // Substitute the values for the type parameters into the type of - // the referenced item. - let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); - - if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { - // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method` - // is inherent, there is no `Self` parameter; instead, the impl needs - // type parameters, which we can infer by unifying the provided `Self` - // with the substituted impl type. - // This also occurs for an enum variant on a type alias. - let ty = tcx.type_of(impl_def_id); - - let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); - match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { - Ok(ok) => self.register_infer_ok_obligations(ok), - Err(_) => { - self.tcx.sess.delay_span_bug( - span, - &format!( - "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", - self_ty, - impl_ty, - ), - ); - } - } - } - - self.check_rustc_args_require_const(def_id, hir_id, span); - - debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted); - self.write_substs(hir_id, substs); - - (ty_substituted, res) - } - - /// Add all the obligations that are required, substituting and normalized appropriately. - fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) { - let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs); - - for (i, mut obligation) in traits::predicates_for_generics( - traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)), - self.param_env, - bounds, - ) - .enumerate() - { - // This makes the error point at the bound, but we want to point at the argument - if let Some(span) = spans.get(i) { - obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span); - } - self.register_predicate(obligation); - } - } - - fn check_rustc_args_require_const(&self, def_id: DefId, hir_id: hir::HirId, span: Span) { - // We're only interested in functions tagged with - // #[rustc_args_required_const], so ignore anything that's not. - if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) { - return; - } - - // If our calling expression is indeed the function itself, we're good! - // If not, generate an error that this can only be called directly. - if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) { - if let ExprKind::Call(ref callee, ..) = expr.kind { - if callee.hir_id == hir_id { - return; - } - } - } - - self.tcx.sess.span_err( - span, - "this function can only be invoked directly, not through a function pointer", - ); - } - - /// Resolves `typ` by a single level if `typ` is a type variable. - /// If no resolution is possible, then an error is reported. - /// Numeric inference variables may be left unresolved. - pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_vars_with_obligations(ty); - if !ty.is_ty_var() { - ty - } else { - if !self.is_tainted_by_errors() { - self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282) - .note("type must be known at this point") - .emit(); - } - let err = self.tcx.ty_error(); - self.demand_suptype(sp, err, ty); - err - } - } - - pub(super) fn with_breakable_ctxt<F: FnOnce() -> R, R>( - &self, - id: hir::HirId, - ctxt: BreakableCtxt<'tcx>, - f: F, - ) -> (BreakableCtxt<'tcx>, R) { - let index; - { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - index = enclosing_breakables.stack.len(); - enclosing_breakables.by_id.insert(id, index); - enclosing_breakables.stack.push(ctxt); - } - let result = f(); - let ctxt = { - let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); - debug_assert!(enclosing_breakables.stack.len() == index + 1); - enclosing_breakables.by_id.remove(&id).expect("missing breakable context"); - enclosing_breakables.stack.pop().expect("missing breakable context") - }; - (ctxt, result) - } - - /// Instantiate a QueryResponse in a probe context, without a - /// good ObligationCause. - pub(super) fn probe_instantiate_query_response( - &self, - span: Span, - original_values: &OriginalQueryValues<'tcx>, - query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, - ) -> InferResult<'tcx, Ty<'tcx>> { - self.instantiate_query_response_and_region_obligations( - &traits::ObligationCause::misc(span, self.body_id), - self.param_env, - original_values, - query_result, - ) - } - - /// Returns `true` if an expression is contained inside the LHS of an assignment expression. - pub(super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { - let mut contained_in_place = false; - - while let hir::Node::Expr(parent_expr) = - self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id)) - { - match &parent_expr.kind { - hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => { - if lhs.hir_id == expr_id { - contained_in_place = true; - break; - } - } - _ => (), - } - expr_id = parent_expr.hir_id; - } - - contained_in_place - } -} -impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { - type Target = Inherited<'a, 'tcx>; - fn deref(&self) -> &Self::Target { - &self.inh - } -} - -impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn item_def_id(&self) -> Option<DefId> { - None - } - - fn default_constness_for_trait_bounds(&self) -> hir::Constness { - // FIXME: refactor this into a method - let node = self.tcx.hir().get(self.body_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { - fn_like.constness() - } else { - hir::Constness::NotConst - } - } - - fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { - let tcx = self.tcx; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_id = tcx.hir().ty_param_owner(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - ty::GenericPredicates { - parent: None, - predicates: tcx.arena.alloc_from_iter( - self.param_env.caller_bounds().iter().filter_map(|predicate| { - match predicate.skip_binders() { - ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { - // HACK(eddyb) should get the original `Span`. - let span = tcx.def_span(def_id); - Some((predicate, span)) - } - _ => None, - } - }), - ), - } - } - - fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { - let v = match def { - Some(def) => infer::EarlyBoundRegion(span, def.name), - None => infer::MiscVariable(span), - }; - Some(self.next_region_var(v)) - } - - fn allow_ty_infer(&self) -> bool { - true - } - - fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { - return ty; - } - unreachable!() - } else { - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }) - } - } - - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> &'tcx Const<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { - return ct; - } - unreachable!() - } else { - self.next_const_var( - ty, - ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, - ) - } - } - - fn projected_ty_from_poly_trait_ref( - &self, - span: Span, - item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Ty<'tcx> { - let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( - span, - infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), - &poly_trait_ref, - ); - - let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item( - self, - self.tcx, - span, - item_def_id, - item_segment, - trait_ref.substs, - ); - - self.tcx().mk_projection(item_def_id, item_substs) - } - - fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_escaping_bound_vars() { - ty // FIXME: normalization and escaping regions - } else { - self.normalize_associated_types_in(span, &ty) - } - } - - fn set_tainted_by_errors(&self) { - self.infcx.set_tainted_by_errors() - } - - fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { - self.write_ty(hir_id, ty) - } -} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs new file mode 100644 index 00000000000..017b0abd1d6 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -0,0 +1,1469 @@ +use crate::astconv::{ + AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, +}; +use crate::check::callee::{self, DeferredCallResolution}; +use crate::check::method::{self, MethodCallee, SelfSource}; +use crate::check::{BreakableCtxt, Diverges, Expectation, FallbackMode, FnCtxt, LocalTy}; + +use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported}; +use rustc_hir as hir; +use rustc_hir::def::{CtorOf, DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{ExprKind, GenericArg, Node, QPath}; +use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; +use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; +use rustc_infer::infer::{InferOk, InferResult}; +use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::{ + self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, +}; +use rustc_middle::ty::{ + self, AdtKind, CanonicalUserType, DefIdTree, GenericParamDefKind, ToPolyTraitRef, ToPredicate, + Ty, UserType, +}; +use rustc_session::lint; +use rustc_span::hygiene::DesugaringKind; +use rustc_span::source_map::{original_sp, DUMMY_SP}; +use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::{self, BytePos, MultiSpan, Span}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; +use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; +use rustc_trait_selection::traits::{self, ObligationCauseCode, TraitEngine, TraitEngineExt}; + +use std::collections::hash_map::Entry; +use std::slice; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + /// Produces warning on the given node, if the current point in the + /// function is unreachable, and there hasn't been another warning. + pub(in super::super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { + // FIXME: Combine these two 'if' expressions into one once + // let chains are implemented + if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { + // If span arose from a desugaring of `if` or `while`, then it is the condition itself, + // which diverges, that we are about to lint on. This gives suboptimal diagnostics. + // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. + if !span.is_desugaring(DesugaringKind::CondTemporary) + && !span.is_desugaring(DesugaringKind::Async) + && !orig_span.is_desugaring(DesugaringKind::Await) + { + self.diverges.set(Diverges::WarnedAlways); + + debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); + + self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { + let msg = format!("unreachable {}", kind); + lint.build(&msg) + .span_label(span, &msg) + .span_label( + orig_span, + custom_note + .unwrap_or("any code following this expression is unreachable"), + ) + .emit(); + }) + } + } + } + + /// Resolves type and const variables in `ty` if possible. Unlike the infcx + /// version (resolve_vars_if_possible), this version will + /// also select obligations if it seems useful, in an effort + /// to get more type information. + pub(in super::super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + debug!("resolve_vars_with_obligations(ty={:?})", ty); + + // No Infer()? Nothing needs doing. + if !ty.has_infer_types_or_consts() { + debug!("resolve_vars_with_obligations: ty={:?}", ty); + return ty; + } + + // If `ty` is a type variable, see whether we already know what it is. + ty = self.resolve_vars_if_possible(&ty); + if !ty.has_infer_types_or_consts() { + debug!("resolve_vars_with_obligations: ty={:?}", ty); + return ty; + } + + // If not, try resolving pending obligations as much as + // possible. This can help substantially when there are + // indirect dependencies that don't seem worth tracking + // precisely. + self.select_obligations_where_possible(false, |_| {}); + ty = self.resolve_vars_if_possible(&ty); + + debug!("resolve_vars_with_obligations: ty={:?}", ty); + ty + } + + pub(in super::super) fn record_deferred_call_resolution( + &self, + closure_def_id: DefId, + r: DeferredCallResolution<'tcx>, + ) { + let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); + deferred_call_resolutions.entry(closure_def_id).or_default().push(r); + } + + pub(in super::super) fn remove_deferred_call_resolutions( + &self, + closure_def_id: DefId, + ) -> Vec<DeferredCallResolution<'tcx>> { + let mut deferred_call_resolutions = self.deferred_call_resolutions.borrow_mut(); + deferred_call_resolutions.remove(&closure_def_id).unwrap_or(vec![]) + } + + pub fn tag(&self) -> String { + format!("{:p}", self) + } + + pub fn local_ty(&self, span: Span, nid: hir::HirId) -> LocalTy<'tcx> { + self.locals.borrow().get(&nid).cloned().unwrap_or_else(|| { + span_bug!(span, "no type for local variable {}", self.tcx.hir().node_to_string(nid)) + }) + } + + #[inline] + pub fn write_ty(&self, id: hir::HirId, ty: Ty<'tcx>) { + debug!( + "write_ty({:?}, {:?}) in fcx {}", + id, + self.resolve_vars_if_possible(&ty), + self.tag() + ); + self.typeck_results.borrow_mut().node_types_mut().insert(id, ty); + + if ty.references_error() { + self.has_errors.set(true); + self.set_tainted_by_errors(); + } + } + + pub fn write_field_index(&self, hir_id: hir::HirId, index: usize) { + self.typeck_results.borrow_mut().field_indices_mut().insert(hir_id, index); + } + + pub(in super::super) fn write_resolution( + &self, + hir_id: hir::HirId, + r: Result<(DefKind, DefId), ErrorReported>, + ) { + self.typeck_results.borrow_mut().type_dependent_defs_mut().insert(hir_id, r); + } + + pub fn write_method_call(&self, hir_id: hir::HirId, method: MethodCallee<'tcx>) { + debug!("write_method_call(hir_id={:?}, method={:?})", hir_id, method); + self.write_resolution(hir_id, Ok((DefKind::AssocFn, method.def_id))); + self.write_substs(hir_id, method.substs); + + // When the method is confirmed, the `method.substs` includes + // parameters from not just the method, but also the impl of + // the method -- in particular, the `Self` type will be fully + // resolved. However, those are not something that the "user + // specified" -- i.e., those types come from the inferred type + // of the receiver, not something the user wrote. So when we + // create the user-substs, we want to replace those earlier + // types with just the types that the user actually wrote -- + // that is, those that appear on the *method itself*. + // + // As an example, if the user wrote something like + // `foo.bar::<u32>(...)` -- the `Self` type here will be the + // type of `foo` (possibly adjusted), but we don't want to + // include that. We want just the `[_, u32]` part. + if !method.substs.is_noop() { + let method_generics = self.tcx.generics_of(method.def_id); + if !method_generics.params.is_empty() { + let user_type_annotation = self.infcx.probe(|_| { + let user_substs = UserSubsts { + substs: InternalSubsts::for_item(self.tcx, method.def_id, |param, _| { + let i = param.index as usize; + if i < method_generics.parent_count { + self.infcx.var_for_def(DUMMY_SP, param) + } else { + method.substs[i] + } + }), + user_self_ty: None, // not relevant here + }; + + self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + method.def_id, + user_substs, + )) + }); + + debug!("write_method_call: user_type_annotation={:?}", user_type_annotation); + self.write_user_type_annotation(hir_id, user_type_annotation); + } + } + } + + pub fn write_substs(&self, node_id: hir::HirId, substs: SubstsRef<'tcx>) { + if !substs.is_noop() { + debug!("write_substs({:?}, {:?}) in fcx {}", node_id, substs, self.tag()); + + self.typeck_results.borrow_mut().node_substs_mut().insert(node_id, substs); + } + } + + /// Given the substs that we just converted from the HIR, try to + /// canonicalize them and store them as user-given substitutions + /// (i.e., substitutions that must be respected by the NLL check). + /// + /// This should be invoked **before any unifications have + /// occurred**, so that annotations like `Vec<_>` are preserved + /// properly. + pub fn write_user_type_annotation_from_substs( + &self, + hir_id: hir::HirId, + def_id: DefId, + substs: SubstsRef<'tcx>, + user_self_ty: Option<UserSelfTy<'tcx>>, + ) { + debug!( + "write_user_type_annotation_from_substs: hir_id={:?} def_id={:?} substs={:?} \ + user_self_ty={:?} in fcx {}", + hir_id, + def_id, + substs, + user_self_ty, + self.tag(), + ); + + if Self::can_contain_user_lifetime_bounds((substs, user_self_ty)) { + let canonicalized = self.infcx.canonicalize_user_type_annotation(&UserType::TypeOf( + def_id, + UserSubsts { substs, user_self_ty }, + )); + debug!("write_user_type_annotation_from_substs: canonicalized={:?}", canonicalized); + self.write_user_type_annotation(hir_id, canonicalized); + } + } + + pub fn write_user_type_annotation( + &self, + hir_id: hir::HirId, + canonical_user_type_annotation: CanonicalUserType<'tcx>, + ) { + debug!( + "write_user_type_annotation: hir_id={:?} canonical_user_type_annotation={:?} tag={}", + hir_id, + canonical_user_type_annotation, + self.tag(), + ); + + if !canonical_user_type_annotation.is_identity() { + self.typeck_results + .borrow_mut() + .user_provided_types_mut() + .insert(hir_id, canonical_user_type_annotation); + } else { + debug!("write_user_type_annotation: skipping identity substs"); + } + } + + pub fn apply_adjustments(&self, expr: &hir::Expr<'_>, adj: Vec<Adjustment<'tcx>>) { + debug!("apply_adjustments(expr={:?}, adj={:?})", expr, adj); + + if adj.is_empty() { + return; + } + + let autoborrow_mut = adj.iter().any(|adj| { + matches!(adj, &Adjustment { + kind: Adjust::Borrow(AutoBorrow::Ref(_, AutoBorrowMutability::Mut { .. })), + .. + }) + }); + + match self.typeck_results.borrow_mut().adjustments_mut().entry(expr.hir_id) { + Entry::Vacant(entry) => { + entry.insert(adj); + } + Entry::Occupied(mut entry) => { + debug!(" - composing on top of {:?}", entry.get()); + match (&entry.get()[..], &adj[..]) { + // Applying any adjustment on top of a NeverToAny + // is a valid NeverToAny adjustment, because it can't + // be reached. + (&[Adjustment { kind: Adjust::NeverToAny, .. }], _) => return, + (&[ + Adjustment { kind: Adjust::Deref(_), .. }, + Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(..)), .. }, + ], &[ + Adjustment { kind: Adjust::Deref(_), .. }, + .. // Any following adjustments are allowed. + ]) => { + // A reborrow has no effect before a dereference. + } + // FIXME: currently we never try to compose autoderefs + // and ReifyFnPointer/UnsafeFnPointer, but we could. + _ => + bug!("while adjusting {:?}, can't compose {:?} and {:?}", + expr, entry.get(), adj) + }; + *entry.get_mut() = adj; + } + } + + // If there is an mutable auto-borrow, it is equivalent to `&mut <expr>`. + // In this case implicit use of `Deref` and `Index` within `<expr>` should + // instead be `DerefMut` and `IndexMut`, so fix those up. + if autoborrow_mut { + self.convert_place_derefs_to_mutable(expr); + } + } + + /// Basically whenever we are converting from a type scheme into + /// the fn body space, we always want to normalize associated + /// types as well. This function combines the two. + fn instantiate_type_scheme<T>(&self, span: Span, substs: SubstsRef<'tcx>, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + let value = value.subst(self.tcx, substs); + let result = self.normalize_associated_types_in(span, &value); + debug!("instantiate_type_scheme(value={:?}, substs={:?}) = {:?}", value, substs, result); + result + } + + /// As `instantiate_type_scheme`, but for the bounds found in a + /// generic type scheme. + pub(in super::super) fn instantiate_bounds( + &self, + span: Span, + def_id: DefId, + substs: SubstsRef<'tcx>, + ) -> (ty::InstantiatedPredicates<'tcx>, Vec<Span>) { + let bounds = self.tcx.predicates_of(def_id); + let spans: Vec<Span> = bounds.predicates.iter().map(|(_, span)| *span).collect(); + let result = bounds.instantiate(self.tcx, substs); + let result = self.normalize_associated_types_in(span, &result); + debug!( + "instantiate_bounds(bounds={:?}, substs={:?}) = {:?}, {:?}", + bounds, substs, result, spans, + ); + (result, spans) + } + + /// Replaces the opaque types from the given value with type variables, + /// and records the `OpaqueTypeMap` for later use during writeback. See + /// `InferCtxt::instantiate_opaque_types` for more details. + pub(in super::super) fn instantiate_opaque_types_from_value<T: TypeFoldable<'tcx>>( + &self, + parent_id: hir::HirId, + value: &T, + value_span: Span, + ) -> T { + let parent_def_id = self.tcx.hir().local_def_id(parent_id); + debug!( + "instantiate_opaque_types_from_value(parent_def_id={:?}, value={:?})", + parent_def_id, value + ); + + let (value, opaque_type_map) = + self.register_infer_ok_obligations(self.instantiate_opaque_types( + parent_def_id, + self.body_id, + self.param_env, + value, + value_span, + )); + + let mut opaque_types = self.opaque_types.borrow_mut(); + let mut opaque_types_vars = self.opaque_types_vars.borrow_mut(); + for (ty, decl) in opaque_type_map { + let _ = opaque_types.insert(ty, decl); + let _ = opaque_types_vars.insert(decl.concrete_ty, decl.opaque_type); + } + + value + } + + pub(in super::super) fn normalize_associated_types_in<T>(&self, span: Span, value: &T) -> T + where + T: TypeFoldable<'tcx>, + { + self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) + } + + pub(in super::super) fn normalize_associated_types_in_as_infer_ok<T>( + &self, + span: Span, + value: &T, + ) -> InferOk<'tcx, T> + where + T: TypeFoldable<'tcx>, + { + self.inh.partially_normalize_associated_types_in(span, self.body_id, self.param_env, value) + } + + pub fn require_type_meets( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + def_id: DefId, + ) { + self.register_bound(ty, def_id, traits::ObligationCause::new(span, self.body_id, code)); + } + + pub fn require_type_is_sized( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); + self.require_type_meets(ty, span, code, lang_item); + } + } + + pub fn require_type_is_sized_deferred( + &self, + ty: Ty<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + if !ty.references_error() { + self.deferred_sized_obligations.borrow_mut().push((ty, span, code)); + } + } + + pub fn register_bound( + &self, + ty: Ty<'tcx>, + def_id: DefId, + cause: traits::ObligationCause<'tcx>, + ) { + if !ty.references_error() { + self.fulfillment_cx.borrow_mut().register_bound( + self, + self.param_env, + ty, + def_id, + cause, + ); + } + } + + pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> Ty<'tcx> { + let t = AstConv::ast_ty_to_ty(self, ast_t); + self.register_wf_obligation(t.into(), ast_t.span, traits::MiscObligation); + t + } + + pub fn to_ty_saving_user_provided_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> { + let ty = self.to_ty(ast_ty); + debug!("to_ty_saving_user_provided_ty: ty={:?}", ty); + + if Self::can_contain_user_lifetime_bounds(ty) { + let c_ty = self.infcx.canonicalize_response(&UserType::Ty(ty)); + debug!("to_ty_saving_user_provided_ty: c_ty={:?}", c_ty); + self.typeck_results.borrow_mut().user_provided_types_mut().insert(ast_ty.hir_id, c_ty); + } + + ty + } + + pub fn to_const(&self, ast_c: &hir::AnonConst) -> &'tcx ty::Const<'tcx> { + let const_def_id = self.tcx.hir().local_def_id(ast_c.hir_id); + let c = ty::Const::from_anon_const(self.tcx, const_def_id); + self.register_wf_obligation( + c.into(), + self.tcx.hir().span(ast_c.hir_id), + ObligationCauseCode::MiscObligation, + ); + c + } + + pub fn const_arg_to_const( + &self, + ast_c: &hir::AnonConst, + param_def_id: DefId, + ) -> &'tcx ty::Const<'tcx> { + let const_def = ty::WithOptConstParam { + did: self.tcx.hir().local_def_id(ast_c.hir_id), + const_param_did: Some(param_def_id), + }; + let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def); + self.register_wf_obligation( + c.into(), + self.tcx.hir().span(ast_c.hir_id), + ObligationCauseCode::MiscObligation, + ); + c + } + + // If the type given by the user has free regions, save it for later, since + // NLL would like to enforce those. Also pass in types that involve + // projections, since those can resolve to `'static` bounds (modulo #54940, + // which hopefully will be fixed by the time you see this comment, dear + // reader, although I have my doubts). Also pass in types with inference + // types, because they may be repeated. Other sorts of things are already + // sufficiently enforced with erased regions. =) + fn can_contain_user_lifetime_bounds<T>(t: T) -> bool + where + T: TypeFoldable<'tcx>, + { + t.has_free_regions() || t.has_projections() || t.has_infer_types() + } + + pub fn node_ty(&self, id: hir::HirId) -> Ty<'tcx> { + match self.typeck_results.borrow().node_types().get(id) { + Some(&t) => t, + None if self.is_tainted_by_errors() => self.tcx.ty_error(), + None => { + bug!( + "no type for node {}: {} in fcx {}", + id, + self.tcx.hir().node_to_string(id), + self.tag() + ); + } + } + } + + /// Registers an obligation for checking later, during regionck, that `arg` is well-formed. + pub fn register_wf_obligation( + &self, + arg: subst::GenericArg<'tcx>, + span: Span, + code: traits::ObligationCauseCode<'tcx>, + ) { + // WF obligations never themselves fail, so no real need to give a detailed cause: + let cause = traits::ObligationCause::new(span, self.body_id, code); + self.register_predicate(traits::Obligation::new( + cause, + self.param_env, + ty::PredicateAtom::WellFormed(arg).to_predicate(self.tcx), + )); + } + + /// Registers obligations that all `substs` are well-formed. + pub fn add_wf_bounds(&self, substs: SubstsRef<'tcx>, expr: &hir::Expr<'_>) { + for arg in substs.iter().filter(|arg| { + matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..)) + }) { + self.register_wf_obligation(arg, expr.span, traits::MiscObligation); + } + } + + /// Given a fully substituted set of bounds (`generic_bounds`), and the values with which each + /// type/region parameter was instantiated (`substs`), creates and registers suitable + /// trait/region obligations. + /// + /// For example, if there is a function: + /// + /// ``` + /// fn foo<'a,T:'a>(...) + /// ``` + /// + /// and a reference: + /// + /// ``` + /// let f = foo; + /// ``` + /// + /// Then we will create a fresh region variable `'$0` and a fresh type variable `$1` for `'a` + /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally. + pub fn add_obligations_for_parameters( + &self, + cause: traits::ObligationCause<'tcx>, + predicates: ty::InstantiatedPredicates<'tcx>, + ) { + assert!(!predicates.has_escaping_bound_vars()); + + debug!("add_obligations_for_parameters(predicates={:?})", predicates); + + for obligation in traits::predicates_for_generics(cause, self.param_env, predicates) { + self.register_predicate(obligation); + } + } + + // FIXME(arielb1): use this instead of field.ty everywhere + // Only for fields! Returns <none> for methods> + // Indifferent to privacy flags + pub fn field_ty( + &self, + span: Span, + field: &'tcx ty::FieldDef, + substs: SubstsRef<'tcx>, + ) -> Ty<'tcx> { + self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) + } + + pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) { + let mut generators = self.deferred_generator_interiors.borrow_mut(); + for (body_id, interior, kind) in generators.drain(..) { + self.select_obligations_where_possible(false, |_| {}); + crate::check::generator_interior::resolve_interior( + self, def_id, body_id, interior, kind, + ); + } + } + + // Tries to apply a fallback to `ty` if it is an unsolved variable. + // + // - Unconstrained ints are replaced with `i32`. + // + // - Unconstrained floats are replaced with with `f64`. + // + // - Non-numerics get replaced with `!` when `#![feature(never_type_fallback)]` + // is enabled. Otherwise, they are replaced with `()`. + // + // Fallback becomes very dubious if we have encountered type-checking errors. + // In that case, fallback to Error. + // The return value indicates whether fallback has occurred. + pub(in super::super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { + use rustc_middle::ty::error::UnconstrainedNumeric::Neither; + use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; + + assert!(ty.is_ty_infer()); + let fallback = match self.type_is_unconstrained_numeric(ty) { + _ if self.is_tainted_by_errors() => self.tcx().ty_error(), + UnconstrainedInt => self.tcx.types.i32, + UnconstrainedFloat => self.tcx.types.f64, + Neither if self.type_var_diverges(ty) => self.tcx.mk_diverging_default(), + Neither => { + // This type variable was created from the instantiation of an opaque + // type. The fact that we're attempting to perform fallback for it + // means that the function neither constrained it to a concrete + // type, nor to the opaque type itself. + // + // For example, in this code: + // + //``` + // type MyType = impl Copy; + // fn defining_use() -> MyType { true } + // fn other_use() -> MyType { defining_use() } + // ``` + // + // `defining_use` will constrain the instantiated inference + // variable to `bool`, while `other_use` will constrain + // the instantiated inference variable to `MyType`. + // + // When we process opaque types during writeback, we + // will handle cases like `other_use`, and not count + // them as defining usages + // + // However, we also need to handle cases like this: + // + // ```rust + // pub type Foo = impl Copy; + // fn produce() -> Option<Foo> { + // None + // } + // ``` + // + // In the above snippet, the inference variable created by + // instantiating `Option<Foo>` will be completely unconstrained. + // We treat this as a non-defining use by making the inference + // variable fall back to the opaque type itself. + if let FallbackMode::All = mode { + if let Some(opaque_ty) = self.opaque_types_vars.borrow().get(ty) { + debug!( + "fallback_if_possible: falling back opaque type var {:?} to {:?}", + ty, opaque_ty + ); + *opaque_ty + } else { + return false; + } + } else { + return false; + } + } + }; + debug!("fallback_if_possible: defaulting `{:?}` to `{:?}`", ty, fallback); + self.demand_eqtype(rustc_span::DUMMY_SP, ty, fallback); + true + } + + pub(in super::super) fn select_all_obligations_or_error(&self) { + debug!("select_all_obligations_or_error"); + if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { + self.report_fulfillment_errors(&errors, self.inh.body_id, false); + } + } + + /// Select as many obligations as we can at present. + pub(in super::super) fn select_obligations_where_possible( + &self, + fallback_has_occurred: bool, + mutate_fullfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>), + ) { + let result = self.fulfillment_cx.borrow_mut().select_where_possible(self); + if let Err(mut errors) = result { + mutate_fullfillment_errors(&mut errors); + self.report_fulfillment_errors(&errors, self.inh.body_id, fallback_has_occurred); + } + } + + /// For the overloaded place expressions (`*x`, `x[3]`), the trait + /// returns a type of `&T`, but the actual type we assign to the + /// *expression* is `T`. So this function just peels off the return + /// type by one layer to yield `T`. + pub(in super::super) fn make_overloaded_place_return_type( + &self, + method: MethodCallee<'tcx>, + ) -> ty::TypeAndMut<'tcx> { + // extract method return type, which will be &T; + let ret_ty = method.sig.output(); + + // method returns &T, but the type as visible to user is T, so deref + ret_ty.builtin_deref(true).unwrap() + } + + fn self_type_matches_expected_vid( + &self, + trait_ref: ty::PolyTraitRef<'tcx>, + expected_vid: ty::TyVid, + ) -> bool { + let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty()); + debug!( + "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", + trait_ref, self_ty, expected_vid + ); + match *self_ty.kind() { + ty::Infer(ty::TyVar(found_vid)) => { + // FIXME: consider using `sub_root_var` here so we + // can see through subtyping. + let found_vid = self.root_var(found_vid); + debug!("self_type_matches_expected_vid - found_vid={:?}", found_vid); + expected_vid == found_vid + } + _ => false, + } + } + + pub(in super::super) fn obligations_for_self_ty<'b>( + &'b self, + self_ty: ty::TyVid, + ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)> + + Captures<'tcx> + + 'b { + // FIXME: consider using `sub_root_var` here so we + // can see through subtyping. + let ty_var_root = self.root_var(self_ty); + debug!( + "obligations_for_self_ty: self_ty={:?} ty_var_root={:?} pending_obligations={:?}", + self_ty, + ty_var_root, + self.fulfillment_cx.borrow().pending_obligations() + ); + + self.fulfillment_cx + .borrow() + .pending_obligations() + .into_iter() + .filter_map(move |obligation| { + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Projection(data) => { + Some((ty::Binder::bind(data).to_poly_trait_ref(self.tcx), obligation)) + } + ty::PredicateAtom::Trait(data, _) => { + Some((ty::Binder::bind(data).to_poly_trait_ref(), obligation)) + } + ty::PredicateAtom::Subtype(..) => None, + ty::PredicateAtom::RegionOutlives(..) => None, + ty::PredicateAtom::TypeOutlives(..) => None, + ty::PredicateAtom::WellFormed(..) => None, + ty::PredicateAtom::ObjectSafe(..) => None, + ty::PredicateAtom::ConstEvaluatable(..) => None, + ty::PredicateAtom::ConstEquate(..) => None, + // N.B., this predicate is created by breaking down a + // `ClosureType: FnFoo()` predicate, where + // `ClosureType` represents some `Closure`. It can't + // possibly be referring to the current closure, + // because we haven't produced the `Closure` for + // this closure yet; this is exactly why the other + // code is looking for a self type of a unresolved + // inference variable. + ty::PredicateAtom::ClosureKind(..) => None, + ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, + } + }) + .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) + } + + pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { + self.obligations_for_self_ty(self_ty) + .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait()) + } + + pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> { + vec![self.tcx.ty_error(); len] + } + + /// Unifies the output type with the expected type early, for more coercions + /// and forward type information on the input expressions. + pub(in super::super) fn expected_inputs_for_expected_output( + &self, + call_span: Span, + expected_ret: Expectation<'tcx>, + formal_ret: Ty<'tcx>, + formal_args: &[Ty<'tcx>], + ) -> Vec<Ty<'tcx>> { + let formal_ret = self.resolve_vars_with_obligations(formal_ret); + let ret_ty = match expected_ret.only_has_type(self) { + Some(ret) => ret, + None => return Vec::new(), + }; + let expect_args = self + .fudge_inference_if_ok(|| { + // Attempt to apply a subtyping relationship between the formal + // return type (likely containing type variables if the function + // is polymorphic) and the expected return type. + // No argument expectations are produced if unification fails. + let origin = self.misc(call_span); + let ures = self.at(&origin, self.param_env).sup(ret_ty, &formal_ret); + + // FIXME(#27336) can't use ? here, Try::from_error doesn't default + // to identity so the resulting type is not constrained. + match ures { + Ok(ok) => { + // Process any obligations locally as much as + // we can. We don't care if some things turn + // out unconstrained or ambiguous, as we're + // just trying to get hints here. + self.save_and_restore_in_snapshot_flag(|_| { + let mut fulfill = TraitEngine::new(self.tcx); + for obligation in ok.obligations { + fulfill.register_predicate_obligation(self, obligation); + } + fulfill.select_where_possible(self) + }) + .map_err(|_| ())?; + } + Err(_) => return Err(()), + } + + // Record all the argument types, with the substitutions + // produced from the above subtyping unification. + Ok(formal_args.iter().map(|ty| self.resolve_vars_if_possible(ty)).collect()) + }) + .unwrap_or_default(); + debug!( + "expected_inputs_for_expected_output(formal={:?} -> {:?}, expected={:?} -> {:?})", + formal_args, formal_ret, expect_args, expected_ret + ); + expect_args + } + + pub(in super::super) fn resolve_lang_item_path( + &self, + lang_item: hir::LangItem, + span: Span, + hir_id: hir::HirId, + ) -> (Res, Ty<'tcx>) { + let def_id = self.tcx.require_lang_item(lang_item, Some(span)); + let def_kind = self.tcx.def_kind(def_id); + + let item_ty = if let DefKind::Variant = def_kind { + self.tcx.type_of(self.tcx.parent(def_id).expect("variant w/out parent")) + } else { + self.tcx.type_of(def_id) + }; + let substs = self.infcx.fresh_substs_for_item(span, def_id); + let ty = item_ty.subst(self.tcx, substs); + + self.write_resolution(hir_id, Ok((def_kind, def_id))); + self.add_required_obligations(span, def_id, &substs); + (Res::Def(def_kind, def_id), ty) + } + + /// Resolves an associated value path into a base type and associated constant, or method + /// resolution. The newly resolved definition is written into `type_dependent_defs`. + pub fn resolve_ty_and_res_ufcs<'b>( + &self, + qpath: &'b QPath<'b>, + hir_id: hir::HirId, + span: Span, + ) -> (Res, Option<Ty<'tcx>>, &'b [hir::PathSegment<'b>]) { + debug!("resolve_ty_and_res_ufcs: qpath={:?} hir_id={:?} span={:?}", qpath, hir_id, span); + let (ty, qself, item_segment) = match *qpath { + QPath::Resolved(ref opt_qself, ref path) => { + return ( + path.res, + opt_qself.as_ref().map(|qself| self.to_ty(qself)), + &path.segments[..], + ); + } + QPath::TypeRelative(ref qself, ref segment) => (self.to_ty(qself), qself, segment), + QPath::LangItem(..) => bug!("`resolve_ty_and_res_ufcs` called on `LangItem`"), + }; + if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id) + { + // Return directly on cache hit. This is useful to avoid doubly reporting + // errors with default match binding modes. See #44614. + let def = + cached_result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err); + return (def, Some(ty), slice::from_ref(&**item_segment)); + } + let item_name = item_segment.ident; + let result = self.resolve_ufcs(span, item_name, ty, hir_id).or_else(|error| { + let result = match error { + method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)), + _ => Err(ErrorReported), + }; + if item_name.name != kw::Invalid { + if let Some(mut e) = self.report_method_error( + span, + ty, + item_name, + SelfSource::QPath(qself), + error, + None, + ) { + e.emit(); + } + } + result + }); + + // Write back the new resolution. + self.write_resolution(hir_id, result); + ( + result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), + Some(ty), + slice::from_ref(&**item_segment), + ) + } + + /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. + pub(in super::super) fn get_node_fn_decl( + &self, + node: Node<'tcx>, + ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { + match node { + Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { + // This is less than ideal, it will not suggest a return type span on any + // method called `main`, regardless of whether it is actually the entry point, + // but it will still present it as the reason for the expected type. + Some((&sig.decl, ident, ident.name != sym::main)) + } + Node::TraitItem(&hir::TraitItem { + ident, + kind: hir::TraitItemKind::Fn(ref sig, ..), + .. + }) => Some((&sig.decl, ident, true)), + Node::ImplItem(&hir::ImplItem { + ident, + kind: hir::ImplItemKind::Fn(ref sig, ..), + .. + }) => Some((&sig.decl, ident, false)), + _ => None, + } + } + + /// Given a `HirId`, return the `FnDecl` of the method it is enclosed by and whether a + /// suggestion can be made, `None` otherwise. + pub fn get_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, bool)> { + // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or + // `while` before reaching it, as block tail returns are not available in them. + self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| { + let parent = self.tcx.hir().get(blk_id); + self.get_node_fn_decl(parent).map(|(fn_decl, _, is_main)| (fn_decl, is_main)) + }) + } + + pub(in super::super) fn note_internal_mutation_in_method( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + if found != self.tcx.types.unit { + return; + } + if let ExprKind::MethodCall(path_segment, _, [rcvr, ..], _) = expr.kind { + if self + .typeck_results + .borrow() + .expr_ty_adjusted_opt(rcvr) + .map_or(true, |ty| expected.peel_refs() != ty.peel_refs()) + { + return; + } + let mut sp = MultiSpan::from_span(path_segment.ident.span); + sp.push_span_label( + path_segment.ident.span, + format!( + "this call modifies {} in-place", + match rcvr.kind { + ExprKind::Path(QPath::Resolved( + None, + hir::Path { segments: [segment], .. }, + )) => format!("`{}`", segment.ident), + _ => "its receiver".to_string(), + } + ), + ); + sp.push_span_label( + rcvr.span, + "you probably want to use this value after calling the method...".to_string(), + ); + err.span_note( + sp, + &format!("method `{}` modifies its receiver in-place", path_segment.ident), + ); + err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident)); + } + } + + pub(in super::super) fn note_need_for_fn_pointer( + &self, + err: &mut DiagnosticBuilder<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + let (sig, did, substs) = match (&expected.kind(), &found.kind()) { + (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { + let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); + let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); + if sig1 != sig2 { + return; + } + err.note( + "different `fn` items always have unique types, even if their signatures are \ + the same", + ); + (sig1, *did1, substs1) + } + (ty::FnDef(did, substs), ty::FnPtr(sig2)) => { + let sig1 = self.tcx.fn_sig(*did).subst(self.tcx, substs); + if sig1 != *sig2 { + return; + } + (sig1, *did, substs) + } + _ => return, + }; + err.help(&format!("change the expected type to be function pointer `{}`", sig)); + err.help(&format!( + "if the expected type is due to type inference, cast the expected `fn` to a function \ + pointer: `{} as {}`", + self.tcx.def_path_str_with_substs(did, substs), + sig + )); + } + + pub(in super::super) fn could_remove_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + ) -> Option<Span> { + // Be helpful when the user wrote `{... expr;}` and + // taking the `;` off is enough to fix the error. + let last_stmt = blk.stmts.last()?; + let last_expr = match last_stmt.kind { + hir::StmtKind::Semi(ref e) => e, + _ => return None, + }; + let last_expr_ty = self.node_ty(last_expr.hir_id); + if matches!(last_expr_ty.kind(), ty::Error(_)) + || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() + { + return None; + } + let original_span = original_sp(last_stmt.span, blk.span); + Some(original_span.with_lo(original_span.hi() - BytePos(1))) + } + + // Instantiates the given path, which must refer to an item with the given + // number of type parameters and type. + pub fn instantiate_value_path( + &self, + segments: &[hir::PathSegment<'_>], + self_ty: Option<Ty<'tcx>>, + res: Res, + span: Span, + hir_id: hir::HirId, + ) -> (Ty<'tcx>, Res) { + debug!( + "instantiate_value_path(segments={:?}, self_ty={:?}, res={:?}, hir_id={})", + segments, self_ty, res, hir_id, + ); + + let tcx = self.tcx; + + let path_segs = match res { + Res::Local(_) | Res::SelfCtor(_) => vec![], + Res::Def(kind, def_id) => { + AstConv::def_ids_for_value_path_segments(self, segments, self_ty, kind, def_id) + } + _ => bug!("instantiate_value_path on {:?}", res), + }; + + let mut user_self_ty = None; + let mut is_alias_variant_ctor = false; + match res { + Res::Def(DefKind::Ctor(CtorOf::Variant, _), _) => { + if let Some(self_ty) = self_ty { + let adt_def = self_ty.ty_adt_def().unwrap(); + user_self_ty = Some(UserSelfTy { impl_def_id: adt_def.did, self_ty }); + is_alias_variant_ctor = true; + } + } + Res::Def(DefKind::AssocFn | DefKind::AssocConst, def_id) => { + let container = tcx.associated_item(def_id).container; + debug!("instantiate_value_path: def_id={:?} container={:?}", def_id, container); + match container { + ty::TraitContainer(trait_did) => { + callee::check_legal_trait_for_method_call(tcx, span, None, trait_did) + } + ty::ImplContainer(impl_def_id) => { + if segments.len() == 1 { + // `<T>::assoc` will end up here, and so + // can `T::assoc`. It this came from an + // inherent impl, we need to record the + // `T` for posterity (see `UserSelfTy` for + // details). + let self_ty = self_ty.expect("UFCS sugared assoc missing Self"); + user_self_ty = Some(UserSelfTy { impl_def_id, self_ty }); + } + } + } + } + _ => {} + } + + // Now that we have categorized what space the parameters for each + // segment belong to, let's sort out the parameters that the user + // provided (if any) into their appropriate spaces. We'll also report + // errors if type parameters are provided in an inappropriate place. + + let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect(); + let generics_has_err = AstConv::prohibit_generics( + self, + segments.iter().enumerate().filter_map(|(index, seg)| { + if !generic_segs.contains(&index) || is_alias_variant_ctor { + Some(seg) + } else { + None + } + }), + ); + + if let Res::Local(hid) = res { + let ty = self.local_ty(span, hid).decl_ty; + let ty = self.normalize_associated_types_in(span, &ty); + self.write_ty(hir_id, ty); + return (ty, res); + } + + if generics_has_err { + // Don't try to infer type parameters when prohibited generic arguments were given. + user_self_ty = None; + } + + // Now we have to compare the types that the user *actually* + // provided against the types that were *expected*. If the user + // did not provide any types, then we want to substitute inference + // variables. If the user provided some types, we may still need + // to add defaults. If the user provided *too many* types, that's + // a problem. + + let mut infer_args_for_err = FxHashSet::default(); + for &PathSeg(def_id, index) in &path_segs { + let seg = &segments[index]; + let generics = tcx.generics_of(def_id); + // Argument-position `impl Trait` is treated as a normal generic + // parameter internally, but we don't allow users to specify the + // parameter's value explicitly, so we have to do some error- + // checking here. + if let GenericArgCountResult { + correct: Err(GenericArgCountMismatch { reported: Some(ErrorReported), .. }), + .. + } = AstConv::check_generic_arg_count_for_call( + tcx, span, &generics, &seg, false, // `is_method_call` + ) { + infer_args_for_err.insert(index); + self.set_tainted_by_errors(); // See issue #53251. + } + } + + let has_self = path_segs + .last() + .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self) + .unwrap_or(false); + + let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { + let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); + match *ty.kind() { + ty::Adt(adt_def, substs) if adt_def.has_ctor() => { + let variant = adt_def.non_enum_variant(); + let ctor_def_id = variant.ctor_def_id.unwrap(); + ( + Res::Def(DefKind::Ctor(CtorOf::Struct, variant.ctor_kind), ctor_def_id), + Some(substs), + ) + } + _ => { + let mut err = tcx.sess.struct_span_err( + span, + "the `Self` constructor can only be used with tuple or unit structs", + ); + if let Some(adt_def) = ty.ty_adt_def() { + match adt_def.adt_kind() { + AdtKind::Enum => { + err.help("did you mean to use one of the enum's variants?"); + } + AdtKind::Struct | AdtKind::Union => { + err.span_suggestion( + span, + "use curly brackets", + String::from("Self { /* fields */ }"), + Applicability::HasPlaceholders, + ); + } + } + } + err.emit(); + + return (tcx.ty_error(), res); + } + } + } else { + (res, None) + }; + let def_id = res.def_id(); + + // The things we are substituting into the type should not contain + // escaping late-bound regions, and nor should the base type scheme. + let ty = tcx.type_of(def_id); + + let arg_count = GenericArgCountResult { + explicit_late_bound: ExplicitLateBound::No, + correct: if infer_args_for_err.is_empty() { + Ok(()) + } else { + Err(GenericArgCountMismatch::default()) + }, + }; + + let substs = self_ctor_substs.unwrap_or_else(|| { + AstConv::create_substs_for_generic_args( + tcx, + def_id, + &[][..], + has_self, + self_ty, + arg_count, + // Provide the generic args, and whether types should be inferred. + |def_id| { + if let Some(&PathSeg(_, index)) = + path_segs.iter().find(|&PathSeg(did, _)| *did == def_id) + { + // If we've encountered an `impl Trait`-related error, we're just + // going to infer the arguments for better error messages. + if !infer_args_for_err.contains(&index) { + // Check whether the user has provided generic arguments. + if let Some(ref data) = segments[index].args { + return (Some(data), segments[index].infer_args); + } + } + return (None, segments[index].infer_args); + } + + (None, true) + }, + // Provide substitutions for parameters for which (valid) arguments have been provided. + |param, arg| match (¶m.kind, arg) { + (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { + AstConv::ast_region_to_region(self, lt, Some(param)).into() + } + (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + self.to_ty(ty).into() + } + (GenericParamDefKind::Const, GenericArg::Const(ct)) => { + self.const_arg_to_const(&ct.value, param.def_id).into() + } + _ => unreachable!(), + }, + // Provide substitutions for parameters for which arguments are inferred. + |substs, param, infer_args| { + match param.kind { + GenericParamDefKind::Lifetime => { + self.re_infer(Some(param), span).unwrap().into() + } + GenericParamDefKind::Type { has_default, .. } => { + if !infer_args && has_default { + // If we have a default, then we it doesn't matter that we're not + // inferring the type arguments: we provide the default where any + // is missing. + let default = tcx.type_of(param.def_id); + self.normalize_ty( + span, + default.subst_spanned(tcx, substs.unwrap(), Some(span)), + ) + .into() + } else { + // If no type arguments were provided, we have to infer them. + // This case also occurs as a result of some malformed input, e.g. + // a lifetime argument being given instead of a type parameter. + // Using inference instead of `Error` gives better error messages. + self.var_for_def(span, param) + } + } + GenericParamDefKind::Const => { + // FIXME(const_generics:defaults) + // No const parameters were provided, we have to infer them. + self.var_for_def(span, param) + } + } + }, + ) + }); + assert!(!substs.has_escaping_bound_vars()); + assert!(!ty.has_escaping_bound_vars()); + + // First, store the "user substs" for later. + self.write_user_type_annotation_from_substs(hir_id, def_id, substs, user_self_ty); + + self.add_required_obligations(span, def_id, &substs); + + // Substitute the values for the type parameters into the type of + // the referenced item. + let ty_substituted = self.instantiate_type_scheme(span, &substs, &ty); + + if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty { + // In the case of `Foo<T>::method` and `<Foo<T>>::method`, if `method` + // is inherent, there is no `Self` parameter; instead, the impl needs + // type parameters, which we can infer by unifying the provided `Self` + // with the substituted impl type. + // This also occurs for an enum variant on a type alias. + let ty = tcx.type_of(impl_def_id); + + let impl_ty = self.instantiate_type_scheme(span, &substs, &ty); + match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { + Ok(ok) => self.register_infer_ok_obligations(ok), + Err(_) => { + self.tcx.sess.delay_span_bug( + span, + &format!( + "instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?", + self_ty, + impl_ty, + ), + ); + } + } + } + + self.check_rustc_args_require_const(def_id, hir_id, span); + + debug!("instantiate_value_path: type of {:?} is {:?}", hir_id, ty_substituted); + self.write_substs(hir_id, substs); + + (ty_substituted, res) + } + + /// Add all the obligations that are required, substituting and normalized appropriately. + fn add_required_obligations(&self, span: Span, def_id: DefId, substs: &SubstsRef<'tcx>) { + let (bounds, spans) = self.instantiate_bounds(span, def_id, &substs); + + for (i, mut obligation) in traits::predicates_for_generics( + traits::ObligationCause::new(span, self.body_id, traits::ItemObligation(def_id)), + self.param_env, + bounds, + ) + .enumerate() + { + // This makes the error point at the bound, but we want to point at the argument + if let Some(span) = spans.get(i) { + obligation.cause.make_mut().code = traits::BindingObligation(def_id, *span); + } + self.register_predicate(obligation); + } + } + + /// Resolves `typ` by a single level if `typ` is a type variable. + /// If no resolution is possible, then an error is reported. + /// Numeric inference variables may be left unresolved. + pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + let ty = self.resolve_vars_with_obligations(ty); + if !ty.is_ty_var() { + ty + } else { + if !self.is_tainted_by_errors() { + self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282) + .note("type must be known at this point") + .emit(); + } + let err = self.tcx.ty_error(); + self.demand_suptype(sp, err, ty); + err + } + } + + pub(in super::super) fn with_breakable_ctxt<F: FnOnce() -> R, R>( + &self, + id: hir::HirId, + ctxt: BreakableCtxt<'tcx>, + f: F, + ) -> (BreakableCtxt<'tcx>, R) { + let index; + { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + index = enclosing_breakables.stack.len(); + enclosing_breakables.by_id.insert(id, index); + enclosing_breakables.stack.push(ctxt); + } + let result = f(); + let ctxt = { + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + debug_assert!(enclosing_breakables.stack.len() == index + 1); + enclosing_breakables.by_id.remove(&id).expect("missing breakable context"); + enclosing_breakables.stack.pop().expect("missing breakable context") + }; + (ctxt, result) + } + + /// Instantiate a QueryResponse in a probe context, without a + /// good ObligationCause. + pub(in super::super) fn probe_instantiate_query_response( + &self, + span: Span, + original_values: &OriginalQueryValues<'tcx>, + query_result: &Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, + ) -> InferResult<'tcx, Ty<'tcx>> { + self.instantiate_query_response_and_region_obligations( + &traits::ObligationCause::misc(span, self.body_id), + self.param_env, + original_values, + query_result, + ) + } + + /// Returns `true` if an expression is contained inside the LHS of an assignment expression. + pub(in super::super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { + let mut contained_in_place = false; + + while let hir::Node::Expr(parent_expr) = + self.tcx.hir().get(self.tcx.hir().get_parent_node(expr_id)) + { + match &parent_expr.kind { + hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => { + if lhs.hir_id == expr_id { + contained_in_place = true; + break; + } + } + _ => (), + } + expr_id = parent_expr.hir_id; + } + + contained_in_place + } +} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs new file mode 100644 index 00000000000..fd2f5eb5018 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -0,0 +1,996 @@ +use crate::astconv::AstConv; +use crate::check::coercion::CoerceMany; +use crate::check::method::MethodCallee; +use crate::check::Expectation::*; +use crate::check::TupleArgumentsFlag::*; +use crate::check::{ + potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, + LocalTy, Needs, TupleArgumentsFlag, +}; + +use rustc_ast as ast; +use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, Res}; +use rustc_hir::def_id::DefId; +use rustc_hir::{ExprKind, Node, QPath}; +use rustc_middle::ty::adjustment::AllowTwoPhase; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty}; +use rustc_session::Session; +use rustc_span::symbol::{sym, Ident}; +use rustc_span::{self, MultiSpan, Span}; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; + +use std::mem::replace; +use std::slice; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub(in super::super) fn check_casts(&self) { + let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); + for cast in deferred_cast_checks.drain(..) { + cast.check(self); + } + } + + pub(in super::super) fn check_method_argument_types( + &self, + sp: Span, + expr: &'tcx hir::Expr<'tcx>, + method: Result<MethodCallee<'tcx>, ()>, + args_no_rcvr: &'tcx [hir::Expr<'tcx>], + tuple_arguments: TupleArgumentsFlag, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let has_error = match method { + Ok(method) => method.substs.references_error() || method.sig.references_error(), + Err(_) => true, + }; + if has_error { + let err_inputs = self.err_args(args_no_rcvr.len()); + + let err_inputs = match tuple_arguments { + DontTupleArguments => err_inputs, + TupleArguments => vec![self.tcx.intern_tup(&err_inputs[..])], + }; + + self.check_argument_types( + sp, + expr, + &err_inputs[..], + &[], + args_no_rcvr, + false, + tuple_arguments, + None, + ); + return self.tcx.ty_error(); + } + + let method = method.unwrap(); + // HACK(eddyb) ignore self in the definition (see above). + let expected_arg_tys = self.expected_inputs_for_expected_output( + sp, + expected, + method.sig.output(), + &method.sig.inputs()[1..], + ); + self.check_argument_types( + sp, + expr, + &method.sig.inputs()[1..], + &expected_arg_tys[..], + args_no_rcvr, + method.sig.c_variadic, + tuple_arguments, + Some(method.def_id), + ); + method.sig.output() + } + + /// Generic function that factors out common logic from function calls, + /// method calls and overloaded operators. + pub(in super::super) fn check_argument_types( + &self, + sp: Span, + expr: &'tcx hir::Expr<'tcx>, + fn_inputs: &[Ty<'tcx>], + expected_arg_tys: &[Ty<'tcx>], + args: &'tcx [hir::Expr<'tcx>], + c_variadic: bool, + tuple_arguments: TupleArgumentsFlag, + def_id: Option<DefId>, + ) { + let tcx = self.tcx; + // Grab the argument types, supplying fresh type variables + // if the wrong number of arguments were supplied + let supplied_arg_count = if tuple_arguments == DontTupleArguments { args.len() } else { 1 }; + + // All the input types from the fn signature must outlive the call + // so as to validate implied bounds. + for (&fn_input_ty, arg_expr) in fn_inputs.iter().zip(args.iter()) { + self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation); + } + + let expected_arg_count = fn_inputs.len(); + + let param_count_error = |expected_count: usize, + arg_count: usize, + error_code: &str, + c_variadic: bool, + sugg_unit: bool| { + let (span, start_span, args) = match &expr.kind { + hir::ExprKind::Call(hir::Expr { span, .. }, args) => (*span, *span, &args[..]), + hir::ExprKind::MethodCall(path_segment, span, args, _) => ( + *span, + // `sp` doesn't point at the whole `foo.bar()`, only at `bar`. + path_segment + .args + .and_then(|args| args.args.iter().last()) + // Account for `foo.bar::<T>()`. + .map(|arg| { + // Skip the closing `>`. + tcx.sess + .source_map() + .next_point(tcx.sess.source_map().next_point(arg.span())) + }) + .unwrap_or(*span), + &args[1..], // Skip the receiver. + ), + k => span_bug!(sp, "checking argument types on a non-call: `{:?}`", k), + }; + let arg_spans = if args.is_empty() { + // foo() + // ^^^-- supplied 0 arguments + // | + // expected 2 arguments + vec![tcx.sess.source_map().next_point(start_span).with_hi(sp.hi())] + } else { + // foo(1, 2, 3) + // ^^^ - - - supplied 3 arguments + // | + // expected 2 arguments + args.iter().map(|arg| arg.span).collect::<Vec<Span>>() + }; + + let mut err = tcx.sess.struct_span_err_with_code( + span, + &format!( + "this function takes {}{} but {} {} supplied", + if c_variadic { "at least " } else { "" }, + potentially_plural_count(expected_count, "argument"), + potentially_plural_count(arg_count, "argument"), + if arg_count == 1 { "was" } else { "were" } + ), + DiagnosticId::Error(error_code.to_owned()), + ); + let label = format!("supplied {}", potentially_plural_count(arg_count, "argument")); + for (i, span) in arg_spans.into_iter().enumerate() { + err.span_label( + span, + if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, + ); + } + + if let Some(def_id) = def_id { + if let Some(node) = tcx.hir().get_if_local(def_id) { + let mut spans: MultiSpan = node + .ident() + .map(|ident| ident.span) + .unwrap_or_else(|| tcx.hir().span(node.hir_id().unwrap())) + .into(); + + if let Some(id) = node.body_id() { + let body = tcx.hir().body(id); + for param in body.params { + spans.push_span_label(param.span, String::new()); + } + } + + let def_kind = tcx.def_kind(def_id); + err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); + } + } + + if sugg_unit { + let sugg_span = tcx.sess.source_map().end_point(expr.span); + // remove closing `)` from the span + let sugg_span = sugg_span.shrink_to_lo(); + err.span_suggestion( + sugg_span, + "expected the unit value `()`; create it with empty parentheses", + String::from("()"), + Applicability::MachineApplicable, + ); + } else { + err.span_label( + span, + format!( + "expected {}{}", + if c_variadic { "at least " } else { "" }, + potentially_plural_count(expected_count, "argument") + ), + ); + } + err.emit(); + }; + + let mut expected_arg_tys = expected_arg_tys.to_vec(); + + let formal_tys = if tuple_arguments == TupleArguments { + let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); + match tuple_type.kind() { + ty::Tuple(arg_types) if arg_types.len() != args.len() => { + param_count_error(arg_types.len(), args.len(), "E0057", false, false); + expected_arg_tys = vec![]; + self.err_args(args.len()) + } + ty::Tuple(arg_types) => { + expected_arg_tys = match expected_arg_tys.get(0) { + Some(&ty) => match ty.kind() { + ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), + _ => vec![], + }, + None => vec![], + }; + arg_types.iter().map(|k| k.expect_ty()).collect() + } + _ => { + struct_span_err!( + tcx.sess, + sp, + E0059, + "cannot use call notation; the first type parameter \ + for the function trait is neither a tuple nor unit" + ) + .emit(); + expected_arg_tys = vec![]; + self.err_args(args.len()) + } + } + } else if expected_arg_count == supplied_arg_count { + fn_inputs.to_vec() + } else if c_variadic { + if supplied_arg_count >= expected_arg_count { + fn_inputs.to_vec() + } else { + param_count_error(expected_arg_count, supplied_arg_count, "E0060", true, false); + expected_arg_tys = vec![]; + self.err_args(supplied_arg_count) + } + } else { + // is the missing argument of type `()`? + let sugg_unit = if expected_arg_tys.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(&expected_arg_tys[0]).is_unit() + } else if fn_inputs.len() == 1 && supplied_arg_count == 0 { + self.resolve_vars_if_possible(&fn_inputs[0]).is_unit() + } else { + false + }; + param_count_error(expected_arg_count, supplied_arg_count, "E0061", false, sugg_unit); + + expected_arg_tys = vec![]; + self.err_args(supplied_arg_count) + }; + + debug!( + "check_argument_types: formal_tys={:?}", + formal_tys.iter().map(|t| self.ty_to_string(*t)).collect::<Vec<String>>() + ); + + // If there is no expectation, expect formal_tys. + let expected_arg_tys = + if !expected_arg_tys.is_empty() { expected_arg_tys } else { formal_tys.clone() }; + + let mut final_arg_types: Vec<(usize, Ty<'_>, Ty<'_>)> = vec![]; + + // Check the arguments. + // We do this in a pretty awful way: first we type-check any arguments + // that are not closures, then we type-check the closures. This is so + // that we have more information about the types of arguments when we + // type-check the functions. This isn't really the right way to do this. + for &check_closures in &[false, true] { + debug!("check_closures={}", check_closures); + + // More awful hacks: before we check argument types, try to do + // an "opportunistic" trait resolution of any trait bounds on + // the call. This helps coercions. + if check_closures { + self.select_obligations_where_possible(false, |errors| { + self.point_at_type_arg_instead_of_call_if_possible(errors, expr); + self.point_at_arg_instead_of_call_if_possible( + errors, + &final_arg_types[..], + sp, + &args, + ); + }) + } + + // For C-variadic functions, we don't have a declared type for all of + // the arguments hence we only do our usual type checking with + // the arguments who's types we do know. + let t = if c_variadic { + expected_arg_count + } else if tuple_arguments == TupleArguments { + args.len() + } else { + supplied_arg_count + }; + for (i, arg) in args.iter().take(t).enumerate() { + // Warn only for the first loop (the "no closures" one). + // Closure arguments themselves can't be diverging, but + // a previous argument can, e.g., `foo(panic!(), || {})`. + if !check_closures { + self.warn_if_unreachable(arg.hir_id, arg.span, "expression"); + } + + let is_closure = match arg.kind { + ExprKind::Closure(..) => true, + _ => false, + }; + + if is_closure != check_closures { + continue; + } + + debug!("checking the argument"); + let formal_ty = formal_tys[i]; + + // The special-cased logic below has three functions: + // 1. Provide as good of an expected type as possible. + let expected = Expectation::rvalue_hint(self, expected_arg_tys[i]); + + let checked_ty = self.check_expr_with_expectation(&arg, expected); + + // 2. Coerce to the most detailed type that could be coerced + // to, which is `expected_ty` if `rvalue_hint` returns an + // `ExpectHasType(expected_ty)`, or the `formal_ty` otherwise. + let coerce_ty = expected.only_has_type(self).unwrap_or(formal_ty); + // We're processing function arguments so we definitely want to use + // two-phase borrows. + self.demand_coerce(&arg, checked_ty, coerce_ty, None, AllowTwoPhase::Yes); + final_arg_types.push((i, checked_ty, coerce_ty)); + + // 3. Relate the expected type and the formal one, + // if the expected type was used for the coercion. + self.demand_suptype(arg.span, formal_ty, coerce_ty); + } + } + + // We also need to make sure we at least write the ty of the other + // arguments which we skipped above. + if c_variadic { + fn variadic_error<'tcx>(s: &Session, span: Span, t: Ty<'tcx>, cast_ty: &str) { + use crate::structured_errors::{StructuredDiagnostic, VariadicError}; + VariadicError::new(s, span, t, cast_ty).diagnostic().emit(); + } + + for arg in args.iter().skip(expected_arg_count) { + let arg_ty = self.check_expr(&arg); + + // There are a few types which get autopromoted when passed via varargs + // in C but we just error out instead and require explicit casts. + let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); + match arg_ty.kind() { + ty::Float(ast::FloatTy::F32) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); + } + ty::Int(ast::IntTy::I8 | ast::IntTy::I16) | ty::Bool => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_int"); + } + ty::Uint(ast::UintTy::U8 | ast::UintTy::U16) => { + variadic_error(tcx.sess, arg.span, arg_ty, "c_uint"); + } + ty::FnDef(..) => { + let ptr_ty = self.tcx.mk_fn_ptr(arg_ty.fn_sig(self.tcx)); + let ptr_ty = self.resolve_vars_if_possible(&ptr_ty); + variadic_error(tcx.sess, arg.span, arg_ty, &ptr_ty.to_string()); + } + _ => {} + } + } + } + } + + // AST fragment checking + pub(in super::super) fn check_lit( + &self, + lit: &hir::Lit, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let tcx = self.tcx; + + match lit.node { + ast::LitKind::Str(..) => tcx.mk_static_str(), + ast::LitKind::ByteStr(ref v) => { + tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.u8, v.len() as u64)) + } + ast::LitKind::Byte(_) => tcx.types.u8, + ast::LitKind::Char(_) => tcx.types.char, + ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), + ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), + ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { + ty::Int(_) | ty::Uint(_) => Some(ty), + ty::Char => Some(tcx.types.u8), + ty::RawPtr(..) => Some(tcx.types.usize), + ty::FnDef(..) | ty::FnPtr(_) => Some(tcx.types.usize), + _ => None, + }); + opt_ty.unwrap_or_else(|| self.next_int_var()) + } + ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t), + ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { + ty::Float(_) => Some(ty), + _ => None, + }); + opt_ty.unwrap_or_else(|| self.next_float_var()) + } + ast::LitKind::Bool(_) => tcx.types.bool, + ast::LitKind::Err(_) => tcx.ty_error(), + } + } + + pub fn check_struct_path( + &self, + qpath: &QPath<'_>, + hir_id: hir::HirId, + ) -> Option<(&'tcx ty::VariantDef, Ty<'tcx>)> { + let path_span = qpath.qself_span(); + let (def, ty) = self.finish_resolving_struct_path(qpath, path_span, hir_id); + let variant = match def { + Res::Err => { + self.set_tainted_by_errors(); + return None; + } + Res::Def(DefKind::Variant, _) => match ty.kind() { + ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)), + _ => bug!("unexpected type: {:?}", ty), + }, + Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) + | Res::SelfTy(..) => match ty.kind() { + ty::Adt(adt, substs) if !adt.is_enum() => { + Some((adt.non_enum_variant(), adt.did, substs)) + } + _ => None, + }, + _ => bug!("unexpected definition: {:?}", def), + }; + + if let Some((variant, did, substs)) = variant { + debug!("check_struct_path: did={:?} substs={:?}", did, substs); + self.write_user_type_annotation_from_substs(hir_id, did, substs, None); + + // Check bounds on type arguments used in the path. + let (bounds, _) = self.instantiate_bounds(path_span, did, substs); + let cause = + traits::ObligationCause::new(path_span, self.body_id, traits::ItemObligation(did)); + self.add_obligations_for_parameters(cause, bounds); + + Some((variant, ty)) + } else { + struct_span_err!( + self.tcx.sess, + path_span, + E0071, + "expected struct, variant or union type, found {}", + ty.sort_string(self.tcx) + ) + .span_label(path_span, "not a struct") + .emit(); + None + } + } + + pub fn check_decl_initializer( + &self, + local: &'tcx hir::Local<'tcx>, + init: &'tcx hir::Expr<'tcx>, + ) -> Ty<'tcx> { + // FIXME(tschottdorf): `contains_explicit_ref_binding()` must be removed + // for #42640 (default match binding modes). + // + // See #44848. + let ref_bindings = local.pat.contains_explicit_ref_binding(); + + let local_ty = self.local_ty(init.span, local.hir_id).revealed_ty; + if let Some(m) = ref_bindings { + // Somewhat subtle: if we have a `ref` binding in the pattern, + // we want to avoid introducing coercions for the RHS. This is + // both because it helps preserve sanity and, in the case of + // ref mut, for soundness (issue #23116). In particular, in + // the latter case, we need to be clear that the type of the + // referent for the reference that results is *equal to* the + // type of the place it is referencing, and not some + // supertype thereof. + let init_ty = self.check_expr_with_needs(init, Needs::maybe_mut_place(m)); + self.demand_eqtype(init.span, local_ty, init_ty); + init_ty + } else { + self.check_expr_coercable_to_type(init, local_ty, None) + } + } + + /// Type check a `let` statement. + pub fn check_decl_local(&self, local: &'tcx hir::Local<'tcx>) { + // Determine and write the type which we'll check the pattern against. + let ty = self.local_ty(local.span, local.hir_id).decl_ty; + self.write_ty(local.hir_id, ty); + + // Type check the initializer. + if let Some(ref init) = local.init { + let init_ty = self.check_decl_initializer(local, &init); + self.overwrite_local_ty_if_err(local, ty, init_ty); + } + + // Does the expected pattern type originate from an expression and what is the span? + let (origin_expr, ty_span) = match (local.ty, local.init) { + (Some(ty), _) => (false, Some(ty.span)), // Bias towards the explicit user type. + (_, Some(init)) => (true, Some(init.span)), // No explicit type; so use the scrutinee. + _ => (false, None), // We have `let $pat;`, so the expected type is unconstrained. + }; + + // Type check the pattern. Override if necessary to avoid knock-on errors. + self.check_pat_top(&local.pat, ty, ty_span, origin_expr); + let pat_ty = self.node_ty(local.pat.hir_id); + self.overwrite_local_ty_if_err(local, ty, pat_ty); + } + + pub fn check_stmt(&self, stmt: &'tcx hir::Stmt<'tcx>) { + // Don't do all the complex logic below for `DeclItem`. + match stmt.kind { + hir::StmtKind::Item(..) => return, + hir::StmtKind::Local(..) | hir::StmtKind::Expr(..) | hir::StmtKind::Semi(..) => {} + } + + self.warn_if_unreachable(stmt.hir_id, stmt.span, "statement"); + + // Hide the outer diverging and `has_errors` flags. + let old_diverges = self.diverges.replace(Diverges::Maybe); + let old_has_errors = self.has_errors.replace(false); + + match stmt.kind { + hir::StmtKind::Local(ref l) => { + self.check_decl_local(&l); + } + // Ignore for now. + hir::StmtKind::Item(_) => {} + hir::StmtKind::Expr(ref expr) => { + // Check with expected type of `()`. + self.check_expr_has_type_or_error(&expr, self.tcx.mk_unit(), |err| { + self.suggest_semicolon_at_end(expr.span, err); + }); + } + hir::StmtKind::Semi(ref expr) => { + self.check_expr(&expr); + } + } + + // Combine the diverging and `has_error` flags. + self.diverges.set(self.diverges.get() | old_diverges); + self.has_errors.set(self.has_errors.get() | old_has_errors); + } + + pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) { + let unit = self.tcx.mk_unit(); + let ty = self.check_block_with_expected(blk, ExpectHasType(unit)); + + // if the block produces a `!` value, that can always be + // (effectively) coerced to unit. + if !ty.is_never() { + self.demand_suptype(blk.span, unit, ty); + } + } + + pub(in super::super) fn check_block_with_expected( + &self, + blk: &'tcx hir::Block<'tcx>, + expected: Expectation<'tcx>, + ) -> Ty<'tcx> { + let prev = { + let mut fcx_ps = self.ps.borrow_mut(); + let unsafety_state = fcx_ps.recurse(blk); + replace(&mut *fcx_ps, unsafety_state) + }; + + // In some cases, blocks have just one exit, but other blocks + // can be targeted by multiple breaks. This can happen both + // with labeled blocks as well as when we desugar + // a `try { ... }` expression. + // + // Example 1: + // + // 'a: { if true { break 'a Err(()); } Ok(()) } + // + // Here we would wind up with two coercions, one from + // `Err(())` and the other from the tail expression + // `Ok(())`. If the tail expression is omitted, that's a + // "forced unit" -- unless the block diverges, in which + // case we can ignore the tail expression (e.g., `'a: { + // break 'a 22; }` would not force the type of the block + // to be `()`). + let tail_expr = blk.expr.as_ref(); + let coerce_to_ty = expected.coercion_target_type(self, blk.span); + let coerce = if blk.targeted_by_break { + CoerceMany::new(coerce_to_ty) + } else { + let tail_expr: &[&hir::Expr<'_>] = match tail_expr { + Some(e) => slice::from_ref(e), + None => &[], + }; + CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr) + }; + + let prev_diverges = self.diverges.get(); + let ctxt = BreakableCtxt { coerce: Some(coerce), may_break: false }; + + let (ctxt, ()) = self.with_breakable_ctxt(blk.hir_id, ctxt, || { + for s in blk.stmts { + self.check_stmt(s); + } + + // check the tail expression **without** holding the + // `enclosing_breakables` lock below. + let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected)); + + let mut enclosing_breakables = self.enclosing_breakables.borrow_mut(); + let ctxt = enclosing_breakables.find_breakable(blk.hir_id); + let coerce = ctxt.coerce.as_mut().unwrap(); + if let Some(tail_expr_ty) = tail_expr_ty { + let tail_expr = tail_expr.unwrap(); + let span = self.get_expr_coercion_span(tail_expr); + let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id)); + coerce.coerce(self, &cause, tail_expr, tail_expr_ty); + } else { + // Subtle: if there is no explicit tail expression, + // that is typically equivalent to a tail expression + // of `()` -- except if the block diverges. In that + // case, there is no value supplied from the tail + // expression (assuming there are no other breaks, + // this implies that the type of the block will be + // `!`). + // + // #41425 -- label the implicit `()` as being the + // "found type" here, rather than the "expected type". + if !self.diverges.get().is_always() { + // #50009 -- Do not point at the entire fn block span, point at the return type + // span, as it is the cause of the requirement, and + // `consider_hint_about_removing_semicolon` will point at the last expression + // if it were a relevant part of the error. This improves usability in editors + // that highlight errors inline. + let mut sp = blk.span; + let mut fn_span = None; + if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) { + let ret_sp = decl.output.span(); + if let Some(block_sp) = self.parent_item_span(blk.hir_id) { + // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the + // output would otherwise be incorrect and even misleading. Make sure + // the span we're aiming at correspond to a `fn` body. + if block_sp == blk.span { + sp = ret_sp; + fn_span = Some(ident.span); + } + } + } + coerce.coerce_forced_unit( + self, + &self.misc(sp), + &mut |err| { + if let Some(expected_ty) = expected.only_has_type(self) { + self.consider_hint_about_removing_semicolon(blk, expected_ty, err); + } + if let Some(fn_span) = fn_span { + err.span_label( + fn_span, + "implicitly returns `()` as its body has no tail or `return` \ + expression", + ); + } + }, + false, + ); + } + } + }); + + if ctxt.may_break { + // If we can break from the block, then the block's exit is always reachable + // (... as long as the entry is reachable) - regardless of the tail of the block. + self.diverges.set(prev_diverges); + } + + let mut ty = ctxt.coerce.unwrap().complete(self); + + if self.has_errors.get() || ty.references_error() { + ty = self.tcx.ty_error() + } + + self.write_ty(blk.hir_id, ty); + + *self.ps.borrow_mut() = prev; + ty + } + + pub(in super::super) fn check_rustc_args_require_const( + &self, + def_id: DefId, + hir_id: hir::HirId, + span: Span, + ) { + // We're only interested in functions tagged with + // #[rustc_args_required_const], so ignore anything that's not. + if !self.tcx.has_attr(def_id, sym::rustc_args_required_const) { + return; + } + + // If our calling expression is indeed the function itself, we're good! + // If not, generate an error that this can only be called directly. + if let Node::Expr(expr) = self.tcx.hir().get(self.tcx.hir().get_parent_node(hir_id)) { + if let ExprKind::Call(ref callee, ..) = expr.kind { + if callee.hir_id == hir_id { + return; + } + } + } + + self.tcx.sess.span_err( + span, + "this function can only be invoked directly, not through a function pointer", + ); + } + + /// A common error is to add an extra semicolon: + /// + /// ``` + /// fn foo() -> usize { + /// 22; + /// } + /// ``` + /// + /// This routine checks if the final statement in a block is an + /// expression with an explicit semicolon whose type is compatible + /// with `expected_ty`. If so, it suggests removing the semicolon. + fn consider_hint_about_removing_semicolon( + &self, + blk: &'tcx hir::Block<'tcx>, + expected_ty: Ty<'tcx>, + err: &mut DiagnosticBuilder<'_>, + ) { + if let Some(span_semi) = self.could_remove_semicolon(blk, expected_ty) { + err.span_suggestion( + span_semi, + "consider removing this semicolon", + String::new(), + Applicability::MachineApplicable, + ); + } + } + + fn parent_item_span(&self, id: hir::HirId) -> Option<Span> { + let node = self.tcx.hir().get(self.tcx.hir().get_parent_item(id)); + match node { + Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, _, body_id), .. }) + | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(_, body_id), .. }) => { + let body = self.tcx.hir().body(body_id); + if let ExprKind::Block(block, _) = &body.value.kind { + return Some(block.span); + } + } + _ => {} + } + None + } + + /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise. + fn get_parent_fn_decl(&self, blk_id: hir::HirId) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> { + let parent = self.tcx.hir().get(self.tcx.hir().get_parent_item(blk_id)); + self.get_node_fn_decl(parent).map(|(fn_decl, ident, _)| (fn_decl, ident)) + } + + /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail + /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors + /// when given code like the following: + /// ```text + /// if false { return 0i32; } else { 1u32 } + /// // ^^^^ point at this instead of the whole `if` expression + /// ``` + fn get_expr_coercion_span(&self, expr: &hir::Expr<'_>) -> rustc_span::Span { + if let hir::ExprKind::Match(_, arms, _) = &expr.kind { + let arm_spans: Vec<Span> = arms + .iter() + .filter_map(|arm| { + self.in_progress_typeck_results + .and_then(|typeck_results| { + typeck_results.borrow().node_type_opt(arm.body.hir_id) + }) + .and_then(|arm_ty| { + if arm_ty.is_never() { + None + } else { + Some(match &arm.body.kind { + // Point at the tail expression when possible. + hir::ExprKind::Block(block, _) => { + block.expr.as_ref().map(|e| e.span).unwrap_or(block.span) + } + _ => arm.body.span, + }) + } + }) + }) + .collect(); + if arm_spans.len() == 1 { + return arm_spans[0]; + } + } + expr.span + } + + fn overwrite_local_ty_if_err( + &self, + local: &'tcx hir::Local<'tcx>, + decl_ty: Ty<'tcx>, + ty: Ty<'tcx>, + ) { + if ty.references_error() { + // Override the types everywhere with `err()` to avoid knock on errors. + self.write_ty(local.hir_id, ty); + self.write_ty(local.pat.hir_id, ty); + let local_ty = LocalTy { decl_ty, revealed_ty: ty }; + self.locals.borrow_mut().insert(local.hir_id, local_ty); + self.locals.borrow_mut().insert(local.pat.hir_id, local_ty); + } + } + + // Finish resolving a path in a struct expression or pattern `S::A { .. }` if necessary. + // The newly resolved definition is written into `type_dependent_defs`. + fn finish_resolving_struct_path( + &self, + qpath: &QPath<'_>, + path_span: Span, + hir_id: hir::HirId, + ) -> (Res, Ty<'tcx>) { + match *qpath { + QPath::Resolved(ref maybe_qself, ref path) => { + let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself)); + let ty = AstConv::res_to_ty(self, self_ty, path, true); + (path.res, ty) + } + QPath::TypeRelative(ref qself, ref segment) => { + let ty = self.to_ty(qself); + + let res = if let hir::TyKind::Path(QPath::Resolved(_, ref path)) = qself.kind { + path.res + } else { + Res::Err + }; + let result = + AstConv::associated_path_to_ty(self, hir_id, path_span, ty, res, segment, true); + let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error()); + let result = result.map(|(_, kind, def_id)| (kind, def_id)); + + // Write back the new resolution. + self.write_resolution(hir_id, result); + + (result.map(|(kind, def_id)| Res::Def(kind, def_id)).unwrap_or(Res::Err), ty) + } + QPath::LangItem(lang_item, span) => { + self.resolve_lang_item_path(lang_item, span, hir_id) + } + } + } + + /// Given a vec of evaluated `FulfillmentError`s and an `fn` call argument expressions, we walk + /// the checked and coerced types for each argument to see if any of the `FulfillmentError`s + /// reference a type argument. The reason to walk also the checked type is that the coerced type + /// can be not easily comparable with predicate type (because of coercion). If the types match + /// for either checked or coerced type, and there's only *one* argument that does, we point at + /// the corresponding argument's expression span instead of the `fn` call path span. + fn point_at_arg_instead_of_call_if_possible( + &self, + errors: &mut Vec<traits::FulfillmentError<'tcx>>, + final_arg_types: &[(usize, Ty<'tcx>, Ty<'tcx>)], + call_sp: Span, + args: &'tcx [hir::Expr<'tcx>], + ) { + // We *do not* do this for desugared call spans to keep good diagnostics when involving + // the `?` operator. + if call_sp.desugaring_kind().is_some() { + return; + } + + for error in errors { + // Only if the cause is somewhere inside the expression we want try to point at arg. + // Otherwise, it means that the cause is somewhere else and we should not change + // anything because we can break the correct span. + if !call_sp.contains(error.obligation.cause.span) { + continue; + } + + if let ty::PredicateAtom::Trait(predicate, _) = + error.obligation.predicate.skip_binders() + { + // Collect the argument position for all arguments that could have caused this + // `FulfillmentError`. + let mut referenced_in = final_arg_types + .iter() + .map(|&(i, checked_ty, _)| (i, checked_ty)) + .chain(final_arg_types.iter().map(|&(i, _, coerced_ty)| (i, coerced_ty))) + .flat_map(|(i, ty)| { + let ty = self.resolve_vars_if_possible(&ty); + // We walk the argument type because the argument's type could have + // been `Option<T>`, but the `FulfillmentError` references `T`. + if ty.walk().any(|arg| arg == predicate.self_ty().into()) { + Some(i) + } else { + None + } + }) + .collect::<Vec<usize>>(); + + // Both checked and coerced types could have matched, thus we need to remove + // duplicates. + + // We sort primitive type usize here and can use unstable sort + referenced_in.sort_unstable(); + referenced_in.dedup(); + + if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { + // We make sure that only *one* argument matches the obligation failure + // and we assign the obligation's span to its expression's. + error.obligation.cause.make_mut().span = args[ref_in].span; + error.points_at_arg_span = true; + } + } + } + } + + /// Given a vec of evaluated `FulfillmentError`s and an `fn` call expression, we walk the + /// `PathSegment`s and resolve their type parameters to see if any of the `FulfillmentError`s + /// were caused by them. If they were, we point at the corresponding type argument's span + /// instead of the `fn` call path span. + fn point_at_type_arg_instead_of_call_if_possible( + &self, + errors: &mut Vec<traits::FulfillmentError<'tcx>>, + call_expr: &'tcx hir::Expr<'tcx>, + ) { + if let hir::ExprKind::Call(path, _) = &call_expr.kind { + if let hir::ExprKind::Path(qpath) = &path.kind { + if let hir::QPath::Resolved(_, path) = &qpath { + for error in errors { + if let ty::PredicateAtom::Trait(predicate, _) = + error.obligation.predicate.skip_binders() + { + // If any of the type arguments in this path segment caused the + // `FullfillmentError`, point at its span (#61860). + for arg in path + .segments + .iter() + .filter_map(|seg| seg.args.as_ref()) + .flat_map(|a| a.args.iter()) + { + if let hir::GenericArg::Type(hir_ty) = &arg { + if let hir::TyKind::Path(hir::QPath::TypeRelative(..)) = + &hir_ty.kind + { + // Avoid ICE with associated types. As this is best + // effort only, it's ok to ignore the case. It + // would trigger in `is_send::<T::AssocType>();` + // from `typeck-default-trait-impl-assoc-type.rs`. + } else { + let ty = AstConv::ast_ty_to_ty(self, hir_ty); + let ty = self.resolve_vars_if_possible(&ty); + if ty == predicate.self_ty() { + error.obligation.cause.make_mut().span = hir_ty.span; + } + } + } + } + } + } + } + } + } + } +} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs new file mode 100644 index 00000000000..72c3b233ed9 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -0,0 +1,295 @@ +mod _impl; +mod checks; +mod suggestions; + +pub use _impl::*; +pub use checks::*; +pub use suggestions::*; + +use crate::astconv::AstConv; +use crate::check::coercion::DynamicCoerceMany; +use crate::check::{Diverges, EnclosingBreakables, Inherited, UnsafetyState}; + +use rustc_hir as hir; +use rustc_hir::def_id::DefId; +use rustc_infer::infer; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; +use rustc_middle::hir::map::blocks::FnLikeNode; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{self, Const, Ty, TyCtxt}; +use rustc_session::Session; +use rustc_span::{self, Span}; +use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; + +use std::cell::{Cell, RefCell}; +use std::ops::Deref; + +pub struct FnCtxt<'a, 'tcx> { + pub(super) body_id: hir::HirId, + + /// The parameter environment used for proving trait obligations + /// in this function. This can change when we descend into + /// closures (as they bring new things into scope), hence it is + /// not part of `Inherited` (as of the time of this writing, + /// closures do not yet change the environment, but they will + /// eventually). + pub(super) param_env: ty::ParamEnv<'tcx>, + + /// Number of errors that had been reported when we started + /// checking this function. On exit, if we find that *more* errors + /// have been reported, we will skip regionck and other work that + /// expects the types within the function to be consistent. + // FIXME(matthewjasper) This should not exist, and it's not correct + // if type checking is run in parallel. + err_count_on_creation: usize, + + /// If `Some`, this stores coercion information for returned + /// expressions. If `None`, this is in a context where return is + /// inappropriate, such as a const expression. + /// + /// This is a `RefCell<DynamicCoerceMany>`, which means that we + /// can track all the return expressions and then use them to + /// compute a useful coercion from the set, similar to a match + /// expression or other branching context. You can use methods + /// like `expected_ty` to access the declared return type (if + /// any). + pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>, + + pub(super) ret_coercion_impl_trait: Option<Ty<'tcx>>, + + pub(super) ret_type_span: Option<Span>, + + /// Used exclusively to reduce cost of advanced evaluation used for + /// more helpful diagnostics. + pub(super) in_tail_expr: bool, + + /// First span of a return site that we find. Used in error messages. + pub(super) ret_coercion_span: RefCell<Option<Span>>, + + pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, + + pub(super) ps: RefCell<UnsafetyState>, + + /// Whether the last checked node generates a divergence (e.g., + /// `return` will set this to `Always`). In general, when entering + /// an expression or other node in the tree, the initial value + /// indicates whether prior parts of the containing expression may + /// have diverged. It is then typically set to `Maybe` (and the + /// old value remembered) for processing the subparts of the + /// current expression. As each subpart is processed, they may set + /// the flag to `Always`, etc. Finally, at the end, we take the + /// result and "union" it with the original value, so that when we + /// return the flag indicates if any subpart of the parent + /// expression (up to and including this part) has diverged. So, + /// if you read it after evaluating a subexpression `X`, the value + /// you get indicates whether any subexpression that was + /// evaluating up to and including `X` diverged. + /// + /// We currently use this flag only for diagnostic purposes: + /// + /// - To warn about unreachable code: if, after processing a + /// sub-expression but before we have applied the effects of the + /// current node, we see that the flag is set to `Always`, we + /// can issue a warning. This corresponds to something like + /// `foo(return)`; we warn on the `foo()` expression. (We then + /// update the flag to `WarnedAlways` to suppress duplicate + /// reports.) Similarly, if we traverse to a fresh statement (or + /// tail expression) from a `Always` setting, we will issue a + /// warning. This corresponds to something like `{return; + /// foo();}` or `{return; 22}`, where we would warn on the + /// `foo()` or `22`. + /// + /// An expression represents dead code if, after checking it, + /// the diverges flag is set to something other than `Maybe`. + pub(super) diverges: Cell<Diverges>, + + /// Whether any child nodes have any type errors. + pub(super) has_errors: Cell<bool>, + + pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>, + + pub(super) inh: &'a Inherited<'a, 'tcx>, +} + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub fn new( + inh: &'a Inherited<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + body_id: hir::HirId, + ) -> FnCtxt<'a, 'tcx> { + FnCtxt { + body_id, + param_env, + err_count_on_creation: inh.tcx.sess.err_count(), + ret_coercion: None, + ret_coercion_impl_trait: None, + ret_type_span: None, + in_tail_expr: false, + ret_coercion_span: RefCell::new(None), + resume_yield_tys: None, + ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), + diverges: Cell::new(Diverges::Maybe), + has_errors: Cell::new(false), + enclosing_breakables: RefCell::new(EnclosingBreakables { + stack: Vec::new(), + by_id: Default::default(), + }), + inh, + } + } + + pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> { + ObligationCause::new(span, self.body_id, code) + } + + pub fn misc(&self, span: Span) -> ObligationCause<'tcx> { + self.cause(span, ObligationCauseCode::MiscObligation) + } + + pub fn sess(&self) -> &Session { + &self.tcx.sess + } + + pub fn errors_reported_since_creation(&self) -> bool { + self.tcx.sess.err_count() > self.err_count_on_creation + } +} + +impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { + type Target = Inherited<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.inh + } +} + +impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + + fn item_def_id(&self) -> Option<DefId> { + None + } + + fn default_constness_for_trait_bounds(&self) -> hir::Constness { + // FIXME: refactor this into a method + let node = self.tcx.hir().get(self.body_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + fn_like.constness() + } else { + hir::Constness::NotConst + } + } + + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + let tcx = self.tcx; + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let item_id = tcx.hir().ty_param_owner(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + ty::GenericPredicates { + parent: None, + predicates: tcx.arena.alloc_from_iter( + self.param_env.caller_bounds().iter().filter_map(|predicate| { + match predicate.skip_binders() { + ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { + // HACK(eddyb) should get the original `Span`. + let span = tcx.def_span(def_id); + Some((predicate, span)) + } + _ => None, + } + }), + ), + } + } + + fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option<ty::Region<'tcx>> { + let v = match def { + Some(def) => infer::EarlyBoundRegion(span, def.name), + None => infer::MiscVariable(span), + }; + Some(self.next_region_var(v)) + } + + fn allow_ty_infer(&self) -> bool { + true + } + + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { + return ty; + } + unreachable!() + } else { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }) + } + } + + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { + return ct; + } + unreachable!() + } else { + self.next_const_var( + ty, + ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, + ) + } + } + + fn projected_ty_from_poly_trait_ref( + &self, + span: Span, + item_def_id: DefId, + item_segment: &hir::PathSegment<'_>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Ty<'tcx> { + let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( + span, + infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), + &poly_trait_ref, + ); + + let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item( + self, + self.tcx, + span, + item_def_id, + item_segment, + trait_ref.substs, + ); + + self.tcx().mk_projection(item_def_id, item_substs) + } + + fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.has_escaping_bound_vars() { + ty // FIXME: normalization and escaping regions + } else { + self.normalize_associated_types_in(span, &ty) + } + } + + fn set_tainted_by_errors(&self) { + self.infcx.set_tainted_by_errors() + } + + fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { + self.write_ty(hir_id, ty) + } +} diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs new file mode 100644 index 00000000000..9bad02c41b4 --- /dev/null +++ b/compiler/rustc_typeck/src/check/fn_ctxt/suggestions.rs @@ -0,0 +1,528 @@ +use super::FnCtxt; +use crate::astconv::AstConv; + +use rustc_ast::util::parser::ExprPrecedence; +use rustc_span::{self, Span}; +use rustc_trait_selection::traits; + +use rustc_errors::{Applicability, DiagnosticBuilder}; +use rustc_hir as hir; +use rustc_hir::def::{CtorOf, DefKind}; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{ExprKind, ItemKind, Node}; +use rustc_infer::infer; +use rustc_middle::ty::{self, Ty}; +use rustc_span::symbol::kw; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; + +use std::iter; + +impl<'a, 'tcx> FnCtxt<'a, 'tcx> { + pub(in super::super) fn suggest_semicolon_at_end( + &self, + span: Span, + err: &mut DiagnosticBuilder<'_>, + ) { + err.span_suggestion_short( + span.shrink_to_hi(), + "consider using a semicolon here", + ";".to_string(), + Applicability::MachineApplicable, + ); + } + + /// On implicit return expressions with mismatched types, provides the following suggestions: + /// + /// - Points out the method's return type as the reason for the expected type. + /// - Possible missing semicolon. + /// - Possible missing return type if the return type is the default, and not `fn main()`. + pub fn suggest_mismatched_types_on_tail( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &'tcx hir::Expr<'tcx>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + cause_span: Span, + blk_id: hir::HirId, + ) -> bool { + let expr = expr.peel_drop_temps(); + self.suggest_missing_semicolon(err, expr, expected, cause_span); + let mut pointing_at_return_type = false; + if let Some((fn_decl, can_suggest)) = self.get_fn_decl(blk_id) { + pointing_at_return_type = + self.suggest_missing_return_type(err, &fn_decl, expected, found, can_suggest); + } + pointing_at_return_type + } + + /// When encountering an fn-like ctor that needs to unify with a value, check whether calling + /// the ctor would successfully solve the type mismatch and if so, suggest it: + /// ``` + /// fn foo(x: usize) -> usize { x } + /// let x: usize = foo; // suggest calling the `foo` function: `foo(42)` + /// ``` + fn suggest_fn_call( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + let hir = self.tcx.hir(); + let (def_id, sig) = match *found.kind() { + ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), + ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()), + _ => return false, + }; + + let sig = self.replace_bound_vars_with_fresh_vars(expr.span, infer::FnCall, &sig).0; + let sig = self.normalize_associated_types_in(expr.span, &sig); + if self.can_coerce(sig.output(), expected) { + let (mut sugg_call, applicability) = if sig.inputs().is_empty() { + (String::new(), Applicability::MachineApplicable) + } else { + ("...".to_string(), Applicability::HasPlaceholders) + }; + let mut msg = "call this function"; + match hir.get_if_local(def_id) { + Some( + Node::Item(hir::Item { kind: ItemKind::Fn(.., body_id), .. }) + | Node::ImplItem(hir::ImplItem { + kind: hir::ImplItemKind::Fn(_, body_id), .. + }) + | Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Provided(body_id)), + .. + }), + ) => { + let body = hir.body(*body_id); + sugg_call = body + .params + .iter() + .map(|param| match ¶m.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => + { + ident.to_string() + } + _ => "_".to_string(), + }) + .collect::<Vec<_>>() + .join(", "); + } + Some(Node::Expr(hir::Expr { + kind: ExprKind::Closure(_, _, body_id, _, _), + span: full_closure_span, + .. + })) => { + if *full_closure_span == expr.span { + return false; + } + msg = "call this closure"; + let body = hir.body(*body_id); + sugg_call = body + .params + .iter() + .map(|param| match ¶m.pat.kind { + hir::PatKind::Binding(_, _, ident, None) + if ident.name != kw::SelfLower => + { + ident.to_string() + } + _ => "_".to_string(), + }) + .collect::<Vec<_>>() + .join(", "); + } + Some(Node::Ctor(hir::VariantData::Tuple(fields, _))) => { + sugg_call = fields.iter().map(|_| "_").collect::<Vec<_>>().join(", "); + match def_id.as_local().map(|def_id| hir.def_kind(def_id)) { + Some(DefKind::Ctor(hir::def::CtorOf::Variant, _)) => { + msg = "instantiate this tuple variant"; + } + Some(DefKind::Ctor(CtorOf::Struct, _)) => { + msg = "instantiate this tuple struct"; + } + _ => {} + } + } + Some(Node::ForeignItem(hir::ForeignItem { + kind: hir::ForeignItemKind::Fn(_, idents, _), + .. + })) => { + sugg_call = idents + .iter() + .map(|ident| { + if ident.name != kw::SelfLower { + ident.to_string() + } else { + "_".to_string() + } + }) + .collect::<Vec<_>>() + .join(", ") + } + Some(Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(.., hir::TraitFn::Required(idents)), + .. + })) => { + sugg_call = idents + .iter() + .map(|ident| { + if ident.name != kw::SelfLower { + ident.to_string() + } else { + "_".to_string() + } + }) + .collect::<Vec<_>>() + .join(", ") + } + _ => {} + } + err.span_suggestion_verbose( + expr.span.shrink_to_hi(), + &format!("use parentheses to {}", msg), + format!("({})", sugg_call), + applicability, + ); + return true; + } + false + } + + pub fn suggest_deref_ref_or_into( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, + ) { + if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { + err.span_suggestion(sp, msg, suggestion, applicability); + } else if let (ty::FnDef(def_id, ..), true) = + (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) + { + if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { + let sp = self.sess().source_map().guess_head_span(sp); + err.span_label(sp, &format!("{} defined here", found)); + } + } else if !self.check_for_cast(err, expr, found, expected, expected_ty_expr) { + let is_struct_pat_shorthand_field = + self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, expr.span); + let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); + if let Ok(expr_text) = self.sess().source_map().span_to_snippet(expr.span) { + let mut suggestions = iter::repeat(&expr_text) + .zip(methods.iter()) + .filter_map(|(receiver, method)| { + let method_call = format!(".{}()", method.ident); + if receiver.ends_with(&method_call) { + None // do not suggest code that is already there (#53348) + } else { + let method_call_list = [".to_vec()", ".to_string()"]; + let sugg = if receiver.ends_with(".clone()") + && method_call_list.contains(&method_call.as_str()) + { + let max_len = receiver.rfind('.').unwrap(); + format!("{}{}", &receiver[..max_len], method_call) + } else { + if expr.precedence().order() < ExprPrecedence::MethodCall.order() { + format!("({}){}", receiver, method_call) + } else { + format!("{}{}", receiver, method_call) + } + }; + Some(if is_struct_pat_shorthand_field { + format!("{}: {}", receiver, sugg) + } else { + sugg + }) + } + }) + .peekable(); + if suggestions.peek().is_some() { + err.span_suggestions( + expr.span, + "try using a conversion method", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + } + } + + /// When encountering the expected boxed value allocated in the stack, suggest allocating it + /// in the heap by calling `Box::new()`. + pub(in super::super) fn suggest_boxing_when_appropriate( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + if self.tcx.hir().is_inside_const_context(expr.hir_id) { + // Do not suggest `Box::new` in const context. + return; + } + if !expected.is_box() || found.is_box() { + return; + } + let boxed_found = self.tcx.mk_box(found); + if let (true, Ok(snippet)) = ( + self.can_coerce(boxed_found, expected), + self.sess().source_map().span_to_snippet(expr.span), + ) { + err.span_suggestion( + expr.span, + "store this in the heap by calling `Box::new`", + format!("Box::new({})", snippet), + Applicability::MachineApplicable, + ); + err.note( + "for more on the distinction between the stack and the heap, read \ + https://doc.rust-lang.org/book/ch15-01-box.html, \ + https://doc.rust-lang.org/rust-by-example/std/box.html, and \ + https://doc.rust-lang.org/std/boxed/index.html", + ); + } + } + + /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. + pub(in super::super) fn suggest_calling_boxed_future_when_appropriate( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) -> bool { + // Handle #68197. + + if self.tcx.hir().is_inside_const_context(expr.hir_id) { + // Do not suggest `Box::new` in const context. + return false; + } + let pin_did = self.tcx.lang_items().pin_type(); + match expected.kind() { + ty::Adt(def, _) if Some(def.did) != pin_did => return false, + // This guards the `unwrap` and `mk_box` below. + _ if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() => return false, + _ => {} + } + let boxed_found = self.tcx.mk_box(found); + let new_found = self.tcx.mk_lang_item(boxed_found, LangItem::Pin).unwrap(); + if let (true, Ok(snippet)) = ( + self.can_coerce(new_found, expected), + self.sess().source_map().span_to_snippet(expr.span), + ) { + match found.kind() { + ty::Adt(def, _) if def.is_box() => { + err.help("use `Box::pin`"); + } + _ => { + err.span_suggestion( + expr.span, + "you need to pin and box this expression", + format!("Box::pin({})", snippet), + Applicability::MachineApplicable, + ); + } + } + true + } else { + false + } + } + + /// A common error is to forget to add a semicolon at the end of a block, e.g., + /// + /// ``` + /// fn foo() { + /// bar_that_returns_u32() + /// } + /// ``` + /// + /// This routine checks if the return expression in a block would make sense on its own as a + /// statement and the return type has been left as default or has been specified as `()`. If so, + /// it suggests adding a semicolon. + fn suggest_missing_semicolon( + &self, + err: &mut DiagnosticBuilder<'_>, + expression: &'tcx hir::Expr<'tcx>, + expected: Ty<'tcx>, + cause_span: Span, + ) { + if expected.is_unit() { + // `BlockTailExpression` only relevant if the tail expr would be + // useful on its own. + match expression.kind { + ExprKind::Call(..) + | ExprKind::MethodCall(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + | ExprKind::Block(..) => { + err.span_suggestion( + cause_span.shrink_to_hi(), + "try adding a semicolon", + ";".to_string(), + Applicability::MachineApplicable, + ); + } + _ => (), + } + } + } + + /// A possible error is to forget to add a return type that is needed: + /// + /// ``` + /// fn foo() { + /// bar_that_returns_u32() + /// } + /// ``` + /// + /// This routine checks if the return type is left as default, the method is not part of an + /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return + /// type. + pub(in super::super) fn suggest_missing_return_type( + &self, + err: &mut DiagnosticBuilder<'_>, + fn_decl: &hir::FnDecl<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + can_suggest: bool, + ) -> bool { + // Only suggest changing the return type for methods that + // haven't set a return type at all (and aren't `fn main()` or an impl). + match (&fn_decl.output, found.is_suggestable(), can_suggest, expected.is_unit()) { + (&hir::FnRetTy::DefaultReturn(span), true, true, true) => { + err.span_suggestion( + span, + "try adding a return type", + format!("-> {} ", self.resolve_vars_with_obligations(found)), + Applicability::MachineApplicable, + ); + true + } + (&hir::FnRetTy::DefaultReturn(span), false, true, true) => { + err.span_label(span, "possibly return type missing here?"); + true + } + (&hir::FnRetTy::DefaultReturn(span), _, false, true) => { + // `fn main()` must return `()`, do not suggest changing return type + err.span_label(span, "expected `()` because of default return type"); + true + } + // expectation was caused by something else, not the default return + (&hir::FnRetTy::DefaultReturn(_), _, _, false) => false, + (&hir::FnRetTy::Return(ref ty), _, _, _) => { + // Only point to return type if the expected type is the return type, as if they + // are not, the expectation must have been caused by something else. + debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind); + let sp = ty.span; + let ty = AstConv::ast_ty_to_ty(self, ty); + debug!("suggest_missing_return_type: return type {:?}", ty); + debug!("suggest_missing_return_type: expected type {:?}", ty); + if ty.kind() == expected.kind() { + err.span_label(sp, format!("expected `{}` because of return type", expected)); + return true; + } + false + } + } + } + + /// A possible error is to forget to add `.await` when using futures: + /// + /// ``` + /// async fn make_u32() -> u32 { + /// 22 + /// } + /// + /// fn take_u32(x: u32) {} + /// + /// async fn foo() { + /// let x = make_u32(); + /// take_u32(x); + /// } + /// ``` + /// + /// This routine checks if the found type `T` implements `Future<Output=U>` where `U` is the + /// expected type. If this is the case, and we are inside of an async body, it suggests adding + /// `.await` to the tail of the expression. + pub(in super::super) fn suggest_missing_await( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + expected: Ty<'tcx>, + found: Ty<'tcx>, + ) { + debug!("suggest_missing_await: expr={:?} expected={:?}, found={:?}", expr, expected, found); + // `.await` is not permitted outside of `async` bodies, so don't bother to suggest if the + // body isn't `async`. + let item_id = self.tcx().hir().get_parent_node(self.body_id); + if let Some(body_id) = self.tcx().hir().maybe_body_owned_by(item_id) { + let body = self.tcx().hir().body(body_id); + if let Some(hir::GeneratorKind::Async(_)) = body.generator_kind { + let sp = expr.span; + // Check for `Future` implementations by constructing a predicate to + // prove: `<T as Future>::Output == U` + let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(sp)); + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + // `<T as Future>::Output` + let projection_ty = ty::ProjectionTy { + // `T` + substs: self + .tcx + .mk_substs_trait(found, self.fresh_substs_for_item(sp, item_def_id)), + // `Future::Output` + item_def_id, + }; + + let predicate = ty::PredicateAtom::Projection(ty::ProjectionPredicate { + projection_ty, + ty: expected, + }) + .potentially_quantified(self.tcx, ty::PredicateKind::ForAll); + let obligation = traits::Obligation::new(self.misc(sp), self.param_env, predicate); + + debug!("suggest_missing_await: trying obligation {:?}", obligation); + + if self.infcx.predicate_may_hold(&obligation) { + debug!("suggest_missing_await: obligation held: {:?}", obligation); + if let Ok(code) = self.sess().source_map().span_to_snippet(sp) { + err.span_suggestion( + sp, + "consider using `.await` here", + format!("{}.await", code), + Applicability::MaybeIncorrect, + ); + } else { + debug!("suggest_missing_await: no snippet for {:?}", sp); + } + } else { + debug!("suggest_missing_await: obligation did not hold: {:?}", obligation) + } + } + } + } + + pub(in super::super) fn suggest_missing_parentheses( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + ) { + let sp = self.tcx.sess.source_map().start_point(expr.span); + if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { + // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` + self.tcx.sess.parse_sess.expr_parentheses_needed(err, *sp, None); + } + } +} diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index 93fdf93e9e3..3fc5f02a4a4 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -8,11 +8,13 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; +use rustc_hir::hir_id::HirIdSet; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, ExprKind, Pat, PatKind}; +use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind}; use rustc_middle::middle::region::{self, YieldData}; use rustc_middle::ty::{self, Ty}; use rustc_span::Span; +use smallvec::SmallVec; struct InteriorVisitor<'a, 'tcx> { fcx: &'a FnCtxt<'a, 'tcx>, @@ -21,6 +23,13 @@ struct InteriorVisitor<'a, 'tcx> { expr_count: usize, kind: hir::GeneratorKind, prev_unresolved_span: Option<Span>, + /// Match arm guards have temporary borrows from the pattern bindings. + /// In case there is a yield point in a guard with a reference to such bindings, + /// such borrows can span across this yield point. + /// As such, we need to track these borrows and record them despite of the fact + /// that they may succeed the said yield point in the post-order. + guard_bindings: SmallVec<[SmallVec<[HirId; 4]>; 1]>, + guard_bindings_set: HirIdSet, } impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { @@ -30,6 +39,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { scope: Option<region::Scope>, expr: Option<&'tcx Expr<'tcx>>, source_span: Span, + guard_borrowing_from_pattern: bool, ) { use rustc_span::DUMMY_SP; @@ -53,7 +63,12 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { yield_data.expr_and_pat_count, self.expr_count, source_span ); - if yield_data.expr_and_pat_count >= self.expr_count { + // If it is a borrowing happening in the guard, + // it needs to be recorded regardless because they + // do live across this yield point. + if guard_borrowing_from_pattern + || yield_data.expr_and_pat_count >= self.expr_count + { Some(yield_data) } else { None @@ -134,6 +149,8 @@ pub fn resolve_interior<'a, 'tcx>( expr_count: 0, kind, prev_unresolved_span: None, + guard_bindings: <_>::default(), + guard_bindings_set: <_>::default(), }; intravisit::walk_body(&mut visitor, body); @@ -210,6 +227,38 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { NestedVisitorMap::None } + fn visit_arm(&mut self, arm: &'tcx Arm<'tcx>) { + let Arm { guard, pat, body, .. } = arm; + self.visit_pat(pat); + if let Some(ref g) = guard { + self.guard_bindings.push(<_>::default()); + ArmPatCollector { + guard_bindings_set: &mut self.guard_bindings_set, + guard_bindings: self + .guard_bindings + .last_mut() + .expect("should have pushed at least one earlier"), + } + .visit_pat(pat); + + match g { + Guard::If(ref e) => { + self.visit_expr(e); + } + } + + let mut scope_var_ids = + self.guard_bindings.pop().expect("should have pushed at least one earlier"); + for var_id in scope_var_ids.drain(..) { + assert!( + self.guard_bindings_set.remove(&var_id), + "variable should be placed in scope earlier" + ); + } + } + self.visit_expr(body); + } + fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { intravisit::walk_pat(self, pat); @@ -218,11 +267,12 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { if let PatKind::Binding(..) = pat.kind { let scope = self.region_scope_tree.var_scope(pat.hir_id.local_id); let ty = self.fcx.typeck_results.borrow().pat_ty(pat); - self.record(ty, Some(scope), None, pat.span); + self.record(ty, Some(scope), None, pat.span, false); } } fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + let mut guard_borrowing_from_pattern = false; match &expr.kind { ExprKind::Call(callee, args) => match &callee.kind { ExprKind::Path(qpath) => { @@ -249,6 +299,16 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { } _ => intravisit::walk_expr(self, expr), }, + ExprKind::Path(qpath) => { + intravisit::walk_expr(self, expr); + let res = self.fcx.typeck_results.borrow().qpath_res(qpath, expr.hir_id); + match res { + Res::Local(id) if self.guard_bindings_set.contains(&id) => { + guard_borrowing_from_pattern = true; + } + _ => {} + } + } _ => intravisit::walk_expr(self, expr), } @@ -259,7 +319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // If there are adjustments, then record the final type -- // this is the actual value that is being produced. if let Some(adjusted_ty) = self.fcx.typeck_results.borrow().expr_ty_adjusted_opt(expr) { - self.record(adjusted_ty, scope, Some(expr), expr.span); + self.record(adjusted_ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); } // Also record the unadjusted type (which is the only type if @@ -267,10 +327,10 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // unadjusted value is sometimes a "temporary" that would wind // up in a MIR temporary. // - // As an example, consider an expression like `vec![].push()`. + // As an example, consider an expression like `vec![].push(x)`. // Here, the `vec![]` would wind up MIR stored into a // temporary variable `t` which we can borrow to invoke - // `<Vec<_>>::push(&mut t)`. + // `<Vec<_>>::push(&mut t, x)`. // // Note that an expression can have many adjustments, and we // are just ignoring those intermediate types. This is because @@ -287,9 +347,30 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> { // The type table might not have information for this expression // if it is in a malformed scope. (#66387) if let Some(ty) = self.fcx.typeck_results.borrow().expr_ty_opt(expr) { - self.record(ty, scope, Some(expr), expr.span); + self.record(ty, scope, Some(expr), expr.span, guard_borrowing_from_pattern); } else { self.fcx.tcx.sess.delay_span_bug(expr.span, "no type for node"); } } } + +struct ArmPatCollector<'a> { + guard_bindings_set: &'a mut HirIdSet, + guard_bindings: &'a mut SmallVec<[HirId; 4]>, +} + +impl<'a, 'tcx> Visitor<'tcx> for ArmPatCollector<'a> { + type Map = intravisit::ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } + + fn visit_pat(&mut self, pat: &'tcx Pat<'tcx>) { + intravisit::walk_pat(self, pat); + if let PatKind::Binding(_, id, ..) = pat.kind { + self.guard_bindings.push(id); + self.guard_bindings_set.insert(id); + } + } +} diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index 97172d391ba..24ffe944128 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -96,7 +96,7 @@ use check::{ pub use check::{check_item_type, check_wf_new}; pub use diverges::Diverges; pub use expectation::Expectation; -pub use fn_ctxt::FnCtxt; +pub use fn_ctxt::*; pub use inherited::{Inherited, InheritedBuilder}; use crate::astconv::AstConv; @@ -264,7 +264,7 @@ pub fn provide(providers: &mut Providers) { } fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::Destructor> { - tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) + tcx.calculate_dtor(def_id, dropck::check_drop_impl) } /// If this `DefId` is a "primary tables entry", returns diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index 2c3be0da5dd..1e97bd65a79 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -202,9 +202,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "analyze_closure: id={:?} substs={:?} final_upvar_tys={:?}", closure_hir_id, substs, final_upvar_tys ); - for (upvar_ty, final_upvar_ty) in substs.upvar_tys().zip(final_upvar_tys) { - self.demand_suptype(span, upvar_ty, final_upvar_ty); - } + + // Build a tuple (U0..Un) of the final upvar types U0..Un + // and unify the upvar tupe type in the closure with it: + let final_tupled_upvars_type = self.tcx.mk_tup(final_upvar_tys.iter()); + self.demand_suptype(span, substs.tupled_upvars_ty(), final_tupled_upvars_type); // If we are also inferred the closure kind here, // process any deferred resolutions. diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index b64a1ce7c30..630e80d502e 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2555,7 +2555,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { ) .emit(); } - if !tcx.sess.target.target.llvm_target.contains("thumbv8m") { + if !tcx.sess.target.llvm_target.contains("thumbv8m") { struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") .emit(); } @@ -2655,7 +2655,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { set.path.segments.iter().map(|x| x.ident.name).collect::<Vec<_>>(); match segments.as_slice() { [sym::arm, sym::a32] | [sym::arm, sym::t32] => { - if !tcx.sess.target.target.options.has_thumb_interworking { + if !tcx.sess.target.options.has_thumb_interworking { struct_span_err!( tcx.sess.diagnostic(), attr.span, diff --git a/config.toml.example b/config.toml.example index 6dc9eccbdfc..e7e37c679e5 100644 --- a/config.toml.example +++ b/config.toml.example @@ -13,7 +13,7 @@ # If it does not match the version that is currently running, # `x.py` will prompt you to update it and read the changelog. # See `src/bootstrap/CHANGELOG.md` for more information. -changelog-seen = 1 +changelog-seen = 2 # ============================================================================= # Global Settings @@ -370,13 +370,13 @@ changelog-seen = 1 # binary, otherwise they are omitted. # # Defaults to rust.debug value -#debug-assertions = debug +#debug-assertions = rust.debug (boolean) # Whether or not debug assertions are enabled for the standard library. # Overrides the `debug-assertions` option, if defined. # # Defaults to rust.debug-assertions value -#debug-assertions-std = debug-assertions +#debug-assertions-std = rust.debug-assertions (boolean) # Whether or not to leave debug! and trace! calls in the rust binary. # Overrides the `debug-assertions` option, if defined. @@ -386,7 +386,7 @@ changelog-seen = 1 # If you see a message from `tracing` saying # `max_level_info` is enabled and means logging won't be shown, # set this value to `true`. -#debug-logging = debug-assertions +#debug-logging = rust.debug-assertions (boolean) # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # `0` - no debug info diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index ce70de6ebdd..109c3a0e683 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -14,8 +14,9 @@ mod tests; extern "Rust" { // These are the magic symbols to call the global allocator. rustc generates - // them from the `#[global_allocator]` attribute if there is one, or uses the - // default implementations in libstd (`__rdl_alloc` etc in `src/libstd/alloc.rs`) + // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute + // (the code expanding that attribute macro generates those functions), or to call + // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`) // otherwise. #[rustc_allocator] #[rustc_allocator_nounwind] @@ -26,8 +27,6 @@ extern "Rust" { fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8; #[rustc_allocator_nounwind] fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_error_handler(size: usize, align: usize) -> !; } /// The global memory allocator. @@ -37,7 +36,7 @@ extern "Rust" { /// if there is one, or the `std` crate’s default. /// /// Note: while this type is unstable, the functionality it provides can be -/// accessed through the [free functions in `alloc`](index.html#functions). +/// accessed through the [free functions in `alloc`](self#functions). #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] pub struct Global; @@ -323,6 +322,16 @@ pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) { } } +// # Allocation error handler + +extern "Rust" { + // This is the magic symbol to call the global alloc error handler. rustc generates + // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the + // default implementations below (`__rdl_oom`) otherwise. + #[rustc_allocator_nounwind] + fn __rust_alloc_error_handler(size: usize, align: usize) -> !; +} + /// Abort on memory allocation error or failure. /// /// Callers of memory allocation APIs wishing to abort computation @@ -367,7 +376,7 @@ pub fn handle_alloc_error(layout: Layout) -> ! { #[doc(hidden)] #[allow(unused_attributes)] #[unstable(feature = "alloc_internals", issue = "none")] -pub mod __default_lib_allocator { +pub mod __alloc_error_handler { use crate::alloc::Layout; // called via generated `__rust_alloc_error_handler` diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 5c8c2c5a5a8..0fc81cb2193 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -815,7 +815,7 @@ impl From<Cow<'_, str>> for Box<str> { #[stable(feature = "boxed_str_conv", since = "1.19.0")] impl From<Box<str>> for Box<[u8]> { - /// Converts a `Box<str>>` into a `Box<[u8]>` + /// Converts a `Box<str>` into a `Box<[u8]>` /// /// This conversion does not allocate on the heap and happens in place. /// diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 880627e94c3..903faf3fa96 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -170,6 +170,22 @@ impl<K, V> Root<K, V> { NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } + /// Borrows and returns a mutable reference to the leaf node owned by the root. + /// # Safety + /// The root node is a leaf. + unsafe fn leaf_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Leaf> { + debug_assert!(self.height == 0); + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } + } + + /// Borrows and returns a mutable reference to the internal node owned by the root. + /// # Safety + /// The root node is not a leaf. + unsafe fn internal_node_as_mut(&mut self) -> NodeRef<marker::Mut<'_>, K, V, marker::Internal> { + debug_assert!(self.height > 0); + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } + } + pub fn node_as_valmut(&mut self) -> NodeRef<marker::ValMut<'_>, K, V, marker::LeafOrInternal> { NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } @@ -188,14 +204,11 @@ impl<K, V> Root<K, V> { self.node = BoxedNode::from_internal(new_node); self.height += 1; - let mut ret = - NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }; - unsafe { + let mut ret = self.internal_node_as_mut(); ret.reborrow_mut().first_edge().correct_parent_link(); + ret } - - ret } /// Removes the internal root node, using its first child as the new root node. @@ -212,11 +225,8 @@ impl<K, V> Root<K, V> { let top = self.node.ptr; - self.node = unsafe { - BoxedNode::from_ptr( - self.node_as_mut().cast_unchecked::<marker::Internal>().first_edge().descend().node, - ) - }; + let internal_node = unsafe { self.internal_node_as_mut() }; + self.node = unsafe { BoxedNode::from_ptr(internal_node.first_edge().descend().node) }; self.height -= 1; self.node_as_mut().as_leaf_mut().parent = None; @@ -247,8 +257,13 @@ impl<K, V> Root<K, V> { /// `NodeRef` points to an internal node, and when this is `LeafOrInternal` the /// `NodeRef` could be pointing to either type of node. pub struct NodeRef<BorrowType, K, V, Type> { - /// The number of levels below the node. + /// The number of levels below the node, a property of the node that cannot be + /// entirely described by `Type` and that the node does not store itself either. + /// Unconstrained if `Type` is `LeafOrInternal`, must be zero if `Type` is `Leaf`, + /// and must be non-zero if `Type` is `Internal`. height: usize, + /// The pointer to the leaf or internal node. The definition of `InternalNode` + /// ensures that the pointer is valid either way. node: NonNull<LeafNode<K, V>>, _marker: PhantomData<(BorrowType, Type)>, } @@ -305,8 +320,8 @@ impl<BorrowType, K, V, Type> NodeRef<BorrowType, K, V, Type> { unsafe { usize::from((*self.as_leaf_ptr()).len) } } - /// Returns the height of this node in the whole tree. Zero height denotes the - /// leaf level. + /// Returns the height of this node with respect to the leaf level. Zero height means the + /// node is a leaf itself. pub fn height(&self) -> usize { self.height } @@ -443,9 +458,9 @@ impl<K, V> NodeRef<marker::Owned, K, V, marker::LeafOrInternal> { } impl<'a, K, V, Type> NodeRef<marker::Mut<'a>, K, V, Type> { - /// Unsafely asserts to the compiler some static information about whether this - /// node is a `Leaf` or an `Internal`. - unsafe fn cast_unchecked<NewType>(self) -> NodeRef<marker::Mut<'a>, K, V, NewType> { + /// Unsafely asserts to the compiler the static information that this node is an `Internal`. + unsafe fn cast_to_internal_unchecked(self) -> NodeRef<marker::Mut<'a>, K, V, marker::Internal> { + debug_assert!(self.height > 0); NodeRef { height: self.height, node: self.node, _marker: PhantomData } } @@ -574,9 +589,11 @@ impl<'a, K, V, Type> NodeRef<marker::ValMut<'a>, K, V, Type> { // to avoid aliasing with outstanding references to other elements, // in particular, those returned to the caller in earlier iterations. let leaf = self.node.as_ptr(); + let keys = unsafe { &raw const (*leaf).keys }; + let vals = unsafe { &raw mut (*leaf).vals }; // We must coerce to unsized array pointers because of Rust issue #74679. - let keys: *const [_] = unsafe { &raw const (*leaf).keys }; - let vals: *mut [_] = unsafe { &raw mut (*leaf).vals }; + let keys: *const [_] = keys; + let vals: *mut [_] = vals; // SAFETY: The keys and values of a node must always be initialized up to length. let key = unsafe { (&*keys.get_unchecked(idx)).assume_init_ref() }; let val = unsafe { (&mut *vals.get_unchecked_mut(idx)).assume_init_mut() }; @@ -807,11 +824,25 @@ impl<BorrowType, K, V, NodeType> Handle<NodeRef<BorrowType, K, V, NodeType>, mar } } +impl<BorrowType, K, V, NodeType> NodeRef<BorrowType, K, V, NodeType> { + /// Could be a public implementation of PartialEq, but only used in this module. + fn eq(&self, other: &Self) -> bool { + let Self { node, height, _marker: _ } = self; + if *node == other.node { + debug_assert_eq!(*height, other.height); + true + } else { + false + } + } +} + impl<BorrowType, K, V, NodeType, HandleType> PartialEq for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType> { fn eq(&self, other: &Self) -> bool { - self.node.node == other.node.node && self.idx == other.idx + let Self { node, idx, _marker: _ } = self; + node.eq(&other.node) && *idx == other.idx } } @@ -819,7 +850,8 @@ impl<BorrowType, K, V, NodeType, HandleType> PartialOrd for Handle<NodeRef<BorrowType, K, V, NodeType>, HandleType> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> { - if self.node.node == other.node.node { Some(self.idx.cmp(&other.idx)) } else { None } + let Self { node, idx, _marker: _ } = self; + if node.eq(&other.node) { Some(idx.cmp(&other.idx)) } else { None } } } @@ -943,10 +975,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, mark Handle::new_edge(left.reborrow_mut(), insert_idx) }, InsertionPlace::Right(insert_idx) => unsafe { - Handle::new_edge( - right.node_as_mut().cast_unchecked::<marker::Leaf>(), - insert_idx, - ) + Handle::new_edge(right.leaf_node_as_mut(), insert_idx) }, }; let val_ptr = insertion_edge.insert_fit(key, val); @@ -1006,10 +1035,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, Handle::new_edge(left.reborrow_mut(), insert_idx) }, InsertionPlace::Right(insert_idx) => unsafe { - Handle::new_edge( - right.node_as_mut().cast_unchecked::<marker::Internal>(), - insert_idx, - ) + Handle::new_edge(right.internal_node_as_mut(), insert_idx) }, }; insertion_edge.insert_fit(key, val, edge); @@ -1205,7 +1231,7 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, let mut new_root = Root { node: BoxedNode::from_internal(new_node), height }; - new_root.node_as_mut().cast_unchecked().correct_childrens_parent_links(0..=new_len); + new_root.internal_node_as_mut().correct_childrens_parent_links(0..=new_len); (self.node, k, v, new_root) } @@ -1258,8 +1284,8 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, if self.node.height > 1 { // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. - let mut left_node = left_node.cast_unchecked::<marker::Internal>(); - let right_node = right_node.cast_unchecked::<marker::Internal>(); + let mut left_node = left_node.cast_to_internal_unchecked(); + let right_node = right_node.cast_to_internal_unchecked(); ptr::copy_nonoverlapping( right_node.edge_at(0), left_node.edges_mut().as_mut_ptr().add(left_len + 1), diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index 54c3709821a..2ef9aad0ccd 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -1,4 +1,5 @@ use super::*; +use core::cmp::Ordering::*; #[test] fn test_splitpoint() { @@ -25,6 +26,38 @@ fn test_splitpoint() { } #[test] +fn test_partial_cmp_eq() { + let mut root1: Root<i32, ()> = Root::new_leaf(); + let mut leaf1 = unsafe { root1.leaf_node_as_mut() }; + leaf1.push(1, ()); + root1.push_internal_level(); + let root2: Root<i32, ()> = Root::new_leaf(); + + let leaf_edge_1a = root1.node_as_ref().first_leaf_edge().forget_node_type(); + let leaf_edge_1b = root1.node_as_ref().last_leaf_edge().forget_node_type(); + let top_edge_1 = root1.node_as_ref().first_edge(); + let top_edge_2 = root2.node_as_ref().first_edge(); + + assert!(leaf_edge_1a == leaf_edge_1a); + assert!(leaf_edge_1a != leaf_edge_1b); + assert!(leaf_edge_1a != top_edge_1); + assert!(leaf_edge_1a != top_edge_2); + assert!(top_edge_1 == top_edge_1); + assert!(top_edge_1 != top_edge_2); + + assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1a), Some(Equal)); + assert_eq!(leaf_edge_1a.partial_cmp(&leaf_edge_1b), Some(Less)); + assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_1), None); + assert_eq!(leaf_edge_1a.partial_cmp(&top_edge_2), None); + assert_eq!(top_edge_1.partial_cmp(&top_edge_1), Some(Equal)); + assert_eq!(top_edge_1.partial_cmp(&top_edge_2), None); + + root1.pop_internal_level(); + unsafe { root1.into_ref().deallocate_and_ascend() }; + unsafe { root2.into_ref().deallocate_and_ascend() }; +} + +#[test] #[cfg(target_arch = "x86_64")] fn test_sizes() { assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16); diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index e8e52299d0b..805e1085cf3 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -1476,7 +1476,8 @@ impl<T> Vec<T> { /// `'a`. If the type has only static references, or none at all, then this /// may be chosen to be `'static`. /// - /// This function is similar to the `leak` function on `Box`. + /// This function is similar to the [`leak`][Box::leak] function on [`Box`] + /// except that there is no way to recover the leaked memory. /// /// This function is mainly useful for data that lives for the remainder of /// the program's life. Dropping the returned reference will cause a memory @@ -1602,50 +1603,6 @@ impl<T: Clone> Vec<T> { } } -impl<T: Default> Vec<T> { - /// Resizes the `Vec` in-place so that `len` is equal to `new_len`. - /// - /// If `new_len` is greater than `len`, the `Vec` is extended by the - /// difference, with each additional slot filled with [`Default::default()`]. - /// If `new_len` is less than `len`, the `Vec` is simply truncated. - /// - /// This method uses [`Default`] to create new values on every push. If - /// you'd rather [`Clone`] a given value, use [`resize`]. - /// - /// # Examples - /// - /// ``` - /// # #![allow(deprecated)] - /// #![feature(vec_resize_default)] - /// - /// let mut vec = vec![1, 2, 3]; - /// vec.resize_default(5); - /// assert_eq!(vec, [1, 2, 3, 0, 0]); - /// - /// let mut vec = vec![1, 2, 3, 4]; - /// vec.resize_default(2); - /// assert_eq!(vec, [1, 2]); - /// ``` - /// - /// [`resize`]: Vec::resize - #[unstable(feature = "vec_resize_default", issue = "41758")] - #[rustc_deprecated( - reason = "This is moving towards being removed in favor \ - of `.resize_with(Default::default)`. If you disagree, please comment \ - in the tracking issue.", - since = "1.33.0" - )] - pub fn resize_default(&mut self, new_len: usize) { - let len = self.len(); - - if new_len > len { - self.extend_with(new_len - len, ExtendDefault); - } else { - self.truncate(new_len); - } - } -} - // This code generalizes `extend_with_{element,default}`. trait ExtendWith<T> { fn next(&mut self) -> T; diff --git a/library/backtrace b/library/backtrace -Subproject 4083a90168d605b682ba166a0c01f86b3384e47 +Subproject a6dd47bd588c882e735675a1379d2b61719fa38 diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 6d09b4f0263..c61c19cc7d1 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -89,13 +89,11 @@ impl fmt::Display for AllocError { pub unsafe trait AllocRef { /// Attempts to allocate a block of memory. /// - /// On success, returns a [`NonNull<[u8]>`] meeting the size and alignment guarantees of `layout`. + /// On success, returns a [`NonNull<[u8]>`][NonNull] meeting the size and alignment guarantees of `layout`. /// /// The returned block may have a larger size than specified by `layout.size()`, and may or may /// not have its contents initialized. /// - /// [`NonNull<[u8]>`]: NonNull - /// /// # Errors /// /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet @@ -146,7 +144,7 @@ pub unsafe trait AllocRef { /// Attempts to extend the memory block. /// - /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated + /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// @@ -158,8 +156,6 @@ pub unsafe trait AllocRef { /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. /// - /// [`NonNull<[u8]>`]: NonNull - /// /// # Safety /// /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. @@ -271,7 +267,7 @@ pub unsafe trait AllocRef { /// Attempts to shrink the memory block. /// - /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated + /// Returns a new [`NonNull<[u8]>`][NonNull] containing a pointer and the actual size of the allocated /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// @@ -283,8 +279,6 @@ pub unsafe trait AllocRef { /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. /// - /// [`NonNull<[u8]>`]: NonNull - /// /// # Safety /// /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 15ec13ca65a..7140218fa91 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -226,7 +226,7 @@ use crate::ptr; /// assert_eq!(my_struct.special_field.get(), new_value); /// ``` /// -/// See the [module-level documentation](index.html) for more. +/// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] #[repr(transparent)] pub struct Cell<T: ?Sized> { @@ -566,7 +566,7 @@ impl<T> Cell<[T]> { /// A mutable memory location with dynamically checked borrow rules /// -/// See the [module-level documentation](index.html) for more. +/// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] pub struct RefCell<T: ?Sized> { borrow: Cell<BorrowFlag>, @@ -1203,7 +1203,7 @@ impl Clone for BorrowRef<'_> { /// Wraps a borrowed reference to a value in a `RefCell` box. /// A wrapper type for an immutably borrowed value from a `RefCell<T>`. /// -/// See the [module-level documentation](index.html) for more. +/// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] pub struct Ref<'b, T: ?Sized + 'b> { value: &'b T, @@ -1493,7 +1493,7 @@ impl<'b> BorrowRefMut<'b> { /// A wrapper type for a mutably borrowed value from a `RefCell<T>`. /// -/// See the [module-level documentation](index.html) for more. +/// See the [module-level documentation](self) for more. #[stable(feature = "rust1", since = "1.0.0")] pub struct RefMut<'b, T: ?Sized + 'b> { value: &'b mut T, diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index 2bfeb49b5fa..3f7110b34cc 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -134,6 +134,7 @@ pub const fn identity<T>(x: T) -> T { /// want to accept all references that can be converted to [`&str`] as an argument. /// Since both [`String`] and [`&str`] implement `AsRef<str>` we can accept both as input argument. /// +/// [`&str`]: primitive@str /// [`Option<T>`]: Option /// [`Result<T, E>`]: Result /// [`Borrow`]: crate::borrow::Borrow diff --git a/library/core/src/ffi.rs b/library/core/src/ffi.rs index 4525ba78ba0..e146a97ae94 100644 --- a/library/core/src/ffi.rs +++ b/library/core/src/ffi.rs @@ -280,7 +280,7 @@ impl<'a, 'f: 'a> DerefMut for VaList<'a, 'f> { // within a private module. Once RFC 2145 has been implemented look into // improving this. mod sealed_trait { - /// Trait which permits the allowed types to be used with [VaList::arg]. + /// Trait which permits the allowed types to be used with [super::VaListImpl::arg]. #[unstable( feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index b2798ea6625..2a7c105e807 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1082,7 +1082,7 @@ extern "rust-intrinsic" { /// If the actual type neither requires drop glue nor implements /// `Copy`, then the return value of this function is unspecified. /// - /// The stabilized version of this intrinsic is [`needs_drop`]. + /// The stabilized version of this intrinsic is [`mem::needs_drop`](crate::mem::needs_drop). #[rustc_const_stable(feature = "const_needs_drop", since = "1.40.0")] pub fn needs_drop<T>() -> bool; diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index 97562cf73b8..44da8f4715c 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -501,9 +501,9 @@ pub fn once_with<A, F: FnOnce() -> A>(gen: F) -> OnceWith<F> { /// /// # Examples /// -/// Let’s re-implement the counter iterator from [module-level documentation]: +/// Let’s re-implement the counter iterator from the [module-level documentation]: /// -/// [module-level documentation]: index.html +/// [module-level documentation]: super /// /// ``` /// let mut count = 0; diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 41a503c4abb..1ae6d15c12d 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -94,7 +94,7 @@ pub trait FromIterator<A>: Sized { /// /// See the [module-level documentation] for more. /// - /// [module-level documentation]: index.html + /// [module-level documentation]: crate::iter /// /// # Examples /// @@ -120,7 +120,7 @@ pub trait FromIterator<A>: Sized { /// collection of some kind. /// /// One benefit of implementing `IntoIterator` is that your type will [work -/// with Rust's `for` loop syntax](index.html#for-loops-and-intoiterator). +/// with Rust's `for` loop syntax](crate::iter#for-loops-and-intoiterator). /// /// See also: [`FromIterator`]. /// @@ -212,7 +212,7 @@ pub trait IntoIterator { /// /// See the [module-level documentation] for more. /// - /// [module-level documentation]: index.html + /// [module-level documentation]: crate::iter /// /// # Examples /// diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 16bee0e2eee..2253648ac2e 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -122,6 +122,9 @@ pub trait DoubleEndedIterator: Iterator { /// assert_eq!(iter.advance_back_by(0), Ok(())); /// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped /// ``` + /// + /// [`Ok(())`]: Ok + /// [`Err(k)`]: Err #[inline] #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs index 33ace60a274..eadbdf45c7c 100644 --- a/library/core/src/iter/traits/exact_size.rs +++ b/library/core/src/iter/traits/exact_size.rs @@ -26,10 +26,10 @@ /// assert_eq!(5, five.len()); /// ``` /// -/// In the [module level docs][moddocs], we implemented an [`Iterator`], -/// `Counter`. Let's implement `ExactSizeIterator` for it as well: +/// In the [module-level docs], we implemented an [`Iterator`], `Counter`. +/// Let's implement `ExactSizeIterator` for it as well: /// -/// [moddocs]: index.html +/// [module-level docs]: crate::iter /// /// ``` /// # struct Counter { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 813afcc0ec6..4af61111128 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -289,12 +289,12 @@ pub trait Iterator { /// This method will eagerly skip `n` elements by calling [`next`] up to `n` /// times until [`None`] is encountered. /// - /// `advance_by(n)` will return [`Ok(())`] if the iterator successfully advances by - /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number + /// `advance_by(n)` will return [`Ok(())`][Ok] if the iterator successfully advances by + /// `n` elements, or [`Err(k)`][Err] if [`None`] is encountered, where `k` is the number /// of elements the iterator is advanced by before running out of elements (i.e. the /// length of the iterator). Note that `k` is always less than `n`. /// - /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`]. + /// Calling `advance_by(0)` does not consume any elements and always returns [`Ok(())`][Ok]. /// /// [`next`]: Iterator::next /// diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 960a26fd283..737a95b603b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -82,7 +82,6 @@ #![feature(const_pin)] #![feature(const_fn)] #![feature(const_fn_union)] -#![feature(const_assume)] #![cfg_attr(not(bootstrap), feature(const_impl_trait))] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] @@ -127,10 +126,12 @@ #![feature(staged_api)] #![feature(std_internals)] #![feature(stmt_expr_attributes)] +#![feature(str_split_as_str)] +#![feature(str_split_inclusive_as_str)] #![feature(transparent_unions)] #![feature(unboxed_closures)] #![feature(unsized_locals)] -#![feature(untagged_unions)] +#![cfg_attr(bootstrap, feature(untagged_unions))] #![feature(unwind_attributes)] #![feature(variant_count)] #![feature(tbm_target_feature)] diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 0cfb4af59b9..825144e5a6f 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -141,6 +141,9 @@ //! ``` //! //! [`Box<T>`]: ../../std/boxed/struct.Box.html +//! [`Box<U>`]: ../../std/boxed/struct.Box.html +//! [`num::NonZero*`]: crate::num +//! [`ptr::NonNull<U>`]: crate::ptr::NonNull #![stable(feature = "rust1", since = "1.0.0")] @@ -684,6 +687,7 @@ impl<T> Option<T> { /// assert_eq!(Some(4).filter(is_even), Some(4)); /// ``` /// + /// [`Some(t)`]: Some #[inline] #[stable(feature = "option_filter", since = "1.27.0")] pub fn filter<P: FnOnce(&T) -> bool>(self, predicate: P) -> Self { diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 92c4f2ccfe8..bca3be56ba5 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -229,6 +229,16 @@ pub(crate) struct FatPtr<T> { pub(crate) len: usize, } +// Manual impl needed to avoid `T: Clone` bound. +impl<T> Clone for FatPtr<T> { + fn clone(&self) -> Self { + *self + } +} + +// Manual impl needed to avoid `T: Copy` bound. +impl<T> Copy for FatPtr<T> {} + /// Forms a raw slice from a pointer and a length. /// /// The `len` argument is the number of **elements**, not the number of bytes. diff --git a/library/core/src/result.rs b/library/core/src/result.rs index 5cec183c237..b6d9f13d881 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -233,7 +233,7 @@ use crate::{convert, fmt}; /// `Result` is a type that represents either success ([`Ok`]) or failure ([`Err`]). /// -/// See the [`std::result`](index.html) module documentation for details. +/// See the [module documentation](self) for details. #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] #[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[rustc_diagnostic_item = "result_type"] diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 13d0dda19c7..349c2cde274 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -79,16 +79,6 @@ pub use index::check_range; #[lang = "slice"] #[cfg(not(test))] impl<T> [T] { - /// The maximum, inclusive, length such that the slice is no larger than `isize::MAX` bytes. - /// This constant is used in `len` below. - const MAX_LEN_BOUND: usize = { - if mem::size_of::<T>() == 0 { - usize::MAX - } else { - isize::MAX as usize / mem::size_of::<T>() - } - }; - /// Returns the number of elements in the slice. /// /// # Examples @@ -101,20 +91,11 @@ impl<T> [T] { #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")] #[inline] // SAFETY: const sound because we transmute out the length field as a usize (which it must be) - #[allow_internal_unstable(const_fn_union, const_assume)] + #[allow_internal_unstable(const_fn_union)] pub const fn len(&self) -> usize { // SAFETY: this is safe because `&[T]` and `FatPtr<T>` have the same layout. // Only `std` can make this guarantee. - let raw_len = unsafe { crate::ptr::Repr { rust: self }.raw.len }; - - // SAFETY: this assume asserts that `raw_len * size_of::<T>() <= isize::MAX`. All - // references must point to one allocation with size at most isize::MAX. Note that we the - // multiplication could appear to overflow until we have assumed the bound. This overflow - // would make additional values appear 'valid' and then `n > 1` the range of permissible - // length would no longer be the full or even a single range. - unsafe { crate::intrinsics::assume(raw_len <= Self::MAX_LEN_BOUND) }; - - raw_len + unsafe { crate::ptr::Repr { rust: self }.raw.len } } /// Returns `true` if the slice has a length of 0. @@ -2054,6 +2035,50 @@ impl<T> [T] { } /// Reorder the slice such that the element at `index` is at its final sorted position. + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable() instead")] + #[inline] + pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where + T: Ord, + { + self.select_nth_unstable(index) + } + + /// Reorder the slice with a comparator function such that the element at `index` is at its + /// final sorted position. + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[rustc_deprecated(since = "1.49.0", reason = "use select_nth_unstable_by() instead")] + #[inline] + pub fn partition_at_index_by<F>( + &mut self, + index: usize, + compare: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T, &T) -> Ordering, + { + self.select_nth_unstable_by(index, compare) + } + + /// Reorder the slice with a key extraction function such that the element at `index` is at its + /// final sorted position. + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[rustc_deprecated(since = "1.49.0", reason = "use the select_nth_unstable_by_key() instead")] + #[inline] + pub fn partition_at_index_by_key<K, F>( + &mut self, + index: usize, + f: F, + ) -> (&mut [T], &mut T, &mut [T]) + where + F: FnMut(&T) -> K, + K: Ord, + { + self.select_nth_unstable_by_key(index, f) + } + + /// Reorder the slice such that the element at `index` is at its final sorted position. /// /// This reordering has the additional property that any value at position `i < index` will be /// less than or equal to any value at a position `j > index`. Additionally, this reordering is @@ -2077,12 +2102,10 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(slice_partition_at_index)] - /// /// let mut v = [-5i32, 4, 1, -3, 2]; /// /// // Find the median - /// v.partition_at_index(2); + /// v.select_nth_unstable(2); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -2091,9 +2114,9 @@ impl<T> [T] { /// v == [-3, -5, 1, 4, 2] || /// v == [-5, -3, 1, 4, 2]); /// ``` - #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] #[inline] - pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + pub fn select_nth_unstable(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) where T: Ord, { @@ -2127,12 +2150,10 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(slice_partition_at_index)] - /// /// let mut v = [-5i32, 4, 1, -3, 2]; /// /// // Find the median as if the slice were sorted in descending order. - /// v.partition_at_index_by(2, |a, b| b.cmp(a)); + /// v.select_nth_unstable_by(2, |a, b| b.cmp(a)); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -2141,9 +2162,9 @@ impl<T> [T] { /// v == [4, 2, 1, -5, -3] || /// v == [4, 2, 1, -3, -5]); /// ``` - #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] #[inline] - pub fn partition_at_index_by<F>( + pub fn select_nth_unstable_by<F>( &mut self, index: usize, mut compare: F, @@ -2181,12 +2202,10 @@ impl<T> [T] { /// # Examples /// /// ``` - /// #![feature(slice_partition_at_index)] - /// /// let mut v = [-5i32, 4, 1, -3, 2]; /// /// // Return the median as if the array were sorted according to absolute value. - /// v.partition_at_index_by_key(2, |a| a.abs()); + /// v.select_nth_unstable_by_key(2, |a| a.abs()); /// /// // We are only guaranteed the slice will be one of the following, based on the way we sort /// // about the specified index. @@ -2195,9 +2214,9 @@ impl<T> [T] { /// v == [2, 1, -3, 4, -5] || /// v == [2, 1, -3, -5, 4]); /// ``` - #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[stable(feature = "slice_select_nth_unstable", since = "1.49.0")] #[inline] - pub fn partition_at_index_by_key<K, F>( + pub fn select_nth_unstable_by_key<K, F>( &mut self, index: usize, mut f: F, diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 27a67e2b22f..bee86df520c 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -690,6 +690,17 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { }, } } + + #[inline] + fn as_str(&self) -> &'a str { + // `Self::get_end` doesn't change `self.start` + if self.finished { + return ""; + } + + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + unsafe { self.matcher.haystack().get_unchecked(self.start..self.end) } + } } generate_pattern_iterators! { @@ -710,6 +721,48 @@ generate_pattern_iterators! { delegate double ended; } +impl<'a, P: Pattern<'a>> Split<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".split(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + +impl<'a, P: Pattern<'a>> RSplit<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".rsplit(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "Mary had a little"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + generate_pattern_iterators! { forward: /// Created with the method [`split_terminator`]. @@ -728,6 +781,48 @@ generate_pattern_iterators! { delegate double ended; } +impl<'a, P: Pattern<'a>> SplitTerminator<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".split_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), ".B.."); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + +impl<'a, P: Pattern<'a>> RSplitTerminator<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "A..B..".rsplit_terminator('.'); + /// assert_eq!(split.as_str(), "A..B.."); + /// split.next(); + /// assert_eq!(split.as_str(), "A..B"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + derive_pattern_clone! { clone SplitNInternal with |s| SplitNInternal { iter: s.iter.clone(), ..*s } @@ -784,6 +879,11 @@ impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { } } } + + #[inline] + fn as_str(&self) -> &'a str { + self.iter.as_str() + } } generate_pattern_iterators! { @@ -804,6 +904,48 @@ generate_pattern_iterators! { delegate single ended; } +impl<'a, P: Pattern<'a>> SplitN<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".splitn(3, ' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + +impl<'a, P: Pattern<'a>> RSplitN<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_as_str)] + /// let mut split = "Mary had a little lamb".rsplitn(3, ' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "Mary had a little"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + derive_pattern_clone! { clone MatchIndicesInternal with |s| MatchIndicesInternal(s.0.clone()) @@ -1134,6 +1276,28 @@ impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator #[unstable(feature = "split_inclusive", issue = "72360")] impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} +impl<'a, P: Pattern<'a>> SplitInclusive<'a, P> { + /// Returns remainder of the splitted string + /// + /// # Examples + /// + /// ``` + /// #![feature(str_split_inclusive_as_str)] + /// #![feature(split_inclusive)] + /// let mut split = "Mary had a little lamb".split_inclusive(' '); + /// assert_eq!(split.as_str(), "Mary had a little lamb"); + /// split.next(); + /// assert_eq!(split.as_str(), "had a little lamb"); + /// split.by_ref().for_each(drop); + /// assert_eq!(split.as_str(), ""); + /// ``` + #[inline] + #[unstable(feature = "str_split_inclusive_as_str", issue = "77998")] + pub fn as_str(&self) -> &'a str { + self.0.as_str() + } +} + /// An iterator of [`u16`] over the string encoded as UTF-16. /// /// This struct is created by the [`encode_utf16`] method on [`str`]. diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 27e6760e7cb..fcb0d6031be 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -204,8 +204,8 @@ macro_rules! int_module { #[test] fn test_from_str() { - fn from_str<T: ::std::str::FromStr>(t: &str) -> Option<T> { - ::std::str::FromStr::from_str(t).ok() + fn from_str<T: std::str::FromStr>(t: &str) -> Option<T> { + std::str::FromStr::from_str(t).ok() } assert_eq!(from_str::<$T>("0"), Some(0 as $T)); assert_eq!(from_str::<$T>("3"), Some(3 as $T)); diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 5ef30b1a889..ac5c9353ccb 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1571,7 +1571,7 @@ fn sort_unstable() { #[test] #[cfg(not(target_arch = "wasm32"))] #[cfg_attr(miri, ignore)] // Miri is too slow -fn partition_at_index() { +fn select_nth_unstable() { use core::cmp::Ordering::{Equal, Greater, Less}; use rand::rngs::StdRng; use rand::seq::SliceRandom; @@ -1597,7 +1597,7 @@ fn partition_at_index() { // Sort in default order. for pivot in 0..len { let mut v = orig.clone(); - v.partition_at_index(pivot); + v.select_nth_unstable(pivot); assert_eq!(v_sorted[pivot], v[pivot]); for i in 0..pivot { @@ -1610,7 +1610,7 @@ fn partition_at_index() { // Sort in ascending order. for pivot in 0..len { let mut v = orig.clone(); - let (left, pivot, right) = v.partition_at_index_by(pivot, |a, b| a.cmp(b)); + let (left, pivot, right) = v.select_nth_unstable_by(pivot, |a, b| a.cmp(b)); assert_eq!(left.len() + right.len(), len - 1); @@ -1633,7 +1633,7 @@ fn partition_at_index() { for pivot in 0..len { let mut v = orig.clone(); - v.partition_at_index_by(pivot, sort_descending_comparator); + v.select_nth_unstable_by(pivot, sort_descending_comparator); assert_eq!(v_sorted_descending[pivot], v[pivot]); for i in 0..pivot { @@ -1654,7 +1654,7 @@ fn partition_at_index() { } for pivot in 0..v.len() { - v.partition_at_index_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); + v.select_nth_unstable_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); v.sort(); for i in 0..v.len() { assert_eq!(v[i], i as i32); @@ -1662,28 +1662,28 @@ fn partition_at_index() { } // Should not panic. - [(); 10].partition_at_index(0); - [(); 10].partition_at_index(5); - [(); 10].partition_at_index(9); - [(); 100].partition_at_index(0); - [(); 100].partition_at_index(50); - [(); 100].partition_at_index(99); + [(); 10].select_nth_unstable(0); + [(); 10].select_nth_unstable(5); + [(); 10].select_nth_unstable(9); + [(); 100].select_nth_unstable(0); + [(); 100].select_nth_unstable(50); + [(); 100].select_nth_unstable(99); let mut v = [0xDEADBEEFu64]; - v.partition_at_index(0); + v.select_nth_unstable(0); assert!(v == [0xDEADBEEF]); } #[test] #[should_panic(expected = "index 0 greater than length of slice")] -fn partition_at_index_zero_length() { - [0i32; 0].partition_at_index(0); +fn select_nth_unstable_zero_length() { + [0i32; 0].select_nth_unstable(0); } #[test] #[should_panic(expected = "index 20 greater than length of slice")] -fn partition_at_index_past_length() { - [0i32; 10].partition_at_index(20); +fn select_nth_unstable_past_length() { + [0i32; 10].select_nth_unstable(20); } pub mod memchr { diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index cc29e1c0b05..a9d8a4e2a81 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -303,7 +303,8 @@ impl Backtrace { // Capture a backtrace which start just before the function addressed by // `ip` fn create(ip: usize) -> Backtrace { - let _lock = lock(); + // SAFETY: We don't attempt to lock this reentrantly. + let _lock = unsafe { lock() }; let mut frames = Vec::new(); let mut actual_start = None; unsafe { @@ -408,7 +409,8 @@ impl Capture { // Use the global backtrace lock to synchronize this as it's a // requirement of the `backtrace` crate, and then actually resolve // everything. - let _lock = lock(); + // SAFETY: We don't attempt to lock this reentrantly. + let _lock = unsafe { lock() }; for frame in self.frames.iter_mut() { let symbols = &mut frame.symbols; let frame = match &frame.frame { diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 13021738af1..6df4eb99259 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -1383,7 +1383,8 @@ impl CStr { /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result. /// - /// [`str`]: prim@str + /// [`str`]: primitive@str + /// [`&str`]: primitive@str /// [`Borrowed`]: Cow::Borrowed /// [`Owned`]: Cow::Owned /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 2663f682a1d..7e7a28be2b0 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -69,7 +69,7 @@ use crate::sys_common::{AsInner, FromInner, IntoInner}; /// [`&OsStr`]: OsStr /// [`&str`]: str /// [`CStr`]: crate::ffi::CStr -/// [conversions]: index.html#conversions +/// [conversions]: super#conversions #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { @@ -88,7 +88,7 @@ pub struct OsString { /// the traits which `OsStr` implements for [conversions] from/to native representations. /// /// [`&str`]: str -/// [conversions]: index.html#conversions +/// [conversions]: super#conversions #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `OsStr::from_inner` current implementation relies diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered.rs deleted file mode 100644 index 97c4b879793..00000000000 --- a/library/std/src/io/buffered.rs +++ /dev/null @@ -1,1438 +0,0 @@ -//! Buffering wrappers for I/O traits - -#[cfg(test)] -mod tests; - -use crate::io::prelude::*; - -use crate::cmp; -use crate::error; -use crate::fmt; -use crate::io::{ - self, Error, ErrorKind, Initializer, IoSlice, IoSliceMut, SeekFrom, DEFAULT_BUF_SIZE, -}; -use crate::memchr; - -/// The `BufReader<R>` struct adds buffering to any reader. -/// -/// It can be excessively inefficient to work directly with a [`Read`] instance. -/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] -/// results in a system call. A `BufReader<R>` performs large, infrequent reads on -/// the underlying [`Read`] and maintains an in-memory buffer of the results. -/// -/// `BufReader<R>` can improve the speed of programs that make *small* and -/// *repeated* read calls to the same file or network socket. It does not -/// help when reading very large amounts at once, or reading just one or a few -/// times. It also provides no advantage when reading from a source that is -/// already in memory, like a [`Vec`]`<u8>`. -/// -/// When the `BufReader<R>` is dropped, the contents of its buffer will be -/// discarded. Creating multiple instances of a `BufReader<R>` on the same -/// stream can cause data loss. Reading from the underlying reader after -/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause -/// data loss. -/// -/// [`TcpStream::read`]: Read::read -/// [`TcpStream`]: crate::net::TcpStream -/// -/// # Examples -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::BufReader; -/// use std::fs::File; -/// -/// fn main() -> std::io::Result<()> { -/// let f = File::open("log.txt")?; -/// let mut reader = BufReader::new(f); -/// -/// let mut line = String::new(); -/// let len = reader.read_line(&mut line)?; -/// println!("First line is {} bytes long", len); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BufReader<R> { - inner: R, - buf: Box<[u8]>, - pos: usize, - cap: usize, -} - -impl<R: Read> BufReader<R> { - /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::new(f); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: R) -> BufReader<R> { - BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufReader<R>` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with ten bytes of capacity: - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let reader = BufReader::with_capacity(10, f); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> { - unsafe { - let mut buffer = Vec::with_capacity(capacity); - buffer.set_len(capacity); - inner.initializer().initialize(&mut buffer); - BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 } - } - } -} - -impl<R> BufReader<R> { - /// Gets a reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); - /// - /// let f2 = reader.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &R { - &self.inner - } - - /// Gets a mutable reference to the underlying reader. - /// - /// It is inadvisable to directly read from the underlying reader. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let mut reader = BufReader::new(f1); - /// - /// let f2 = reader.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut R { - &mut self.inner - } - - /// Returns a reference to the internally buffered data. - /// - /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty. - /// - /// [`fill_buf`]: BufRead::fill_buf - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{BufReader, BufRead}; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let mut reader = BufReader::new(f); - /// assert!(reader.buffer().is_empty()); - /// - /// if reader.fill_buf()?.len() > 0 { - /// assert!(!reader.buffer().is_empty()); - /// } - /// Ok(()) - /// } - /// ``` - #[stable(feature = "bufreader_buffer", since = "1.37.0")] - pub fn buffer(&self) -> &[u8] { - &self.buf[self.pos..self.cap] - } - - /// Returns the number of bytes the internal buffer can hold at once. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::{BufReader, BufRead}; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::open("log.txt")?; - /// let mut reader = BufReader::new(f); - /// - /// let capacity = reader.capacity(); - /// let buffer = reader.fill_buf()?; - /// assert!(buffer.len() <= capacity); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "buffered_io_capacity", since = "1.46.0")] - pub fn capacity(&self) -> usize { - self.buf.len() - } - - /// Unwraps this `BufReader<R>`, returning the underlying reader. - /// - /// Note that any leftover data in the internal buffer is lost. Therefore, - /// a following read from the underlying reader may lead to data loss. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufReader; - /// use std::fs::File; - /// - /// fn main() -> std::io::Result<()> { - /// let f1 = File::open("log.txt")?; - /// let reader = BufReader::new(f1); - /// - /// let f2 = reader.into_inner(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> R { - self.inner - } - - /// Invalidates all data in the internal buffer. - #[inline] - fn discard_buffer(&mut self) { - self.pos = 0; - self.cap = 0; - } -} - -impl<R: Seek> BufReader<R> { - /// Seeks relative to the current position. If the new position lies within the buffer, - /// the buffer will not be flushed, allowing for more efficient seeks. - /// This method does not return the location of the underlying reader, so the caller - /// must track this information themselves if it is required. - #[unstable(feature = "bufreader_seek_relative", issue = "31100")] - pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { - let pos = self.pos as u64; - if offset < 0 { - if let Some(new_pos) = pos.checked_sub((-offset) as u64) { - self.pos = new_pos as usize; - return Ok(()); - } - } else { - if let Some(new_pos) = pos.checked_add(offset as u64) { - if new_pos <= self.cap as u64 { - self.pos = new_pos as usize; - return Ok(()); - } - } - } - self.seek(SeekFrom::Current(offset)).map(drop) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<R: Read> Read for BufReader<R> { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - // If we don't have any buffered data and we're doing a massive read - // (larger than our internal buffer), bypass our internal buffer - // entirely. - if self.pos == self.cap && buf.len() >= self.buf.len() { - self.discard_buffer(); - return self.inner.read(buf); - } - let nread = { - let mut rem = self.fill_buf()?; - rem.read(buf)? - }; - self.consume(nread); - Ok(nread) - } - - fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); - if self.pos == self.cap && total_len >= self.buf.len() { - self.discard_buffer(); - return self.inner.read_vectored(bufs); - } - let nread = { - let mut rem = self.fill_buf()?; - rem.read_vectored(bufs)? - }; - self.consume(nread); - Ok(nread) - } - - fn is_read_vectored(&self) -> bool { - self.inner.is_read_vectored() - } - - // we can't skip unconditionally because of the large buffer case in read. - unsafe fn initializer(&self) -> Initializer { - self.inner.initializer() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<R: Read> BufRead for BufReader<R> { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - // If we've reached the end of our internal buffer then we need to fetch - // some more data from the underlying reader. - // Branch using `>=` instead of the more correct `==` - // to tell the compiler that the pos..cap slice is always valid. - if self.pos >= self.cap { - debug_assert!(self.pos == self.cap); - self.cap = self.inner.read(&mut self.buf)?; - self.pos = 0; - } - Ok(&self.buf[self.pos..self.cap]) - } - - fn consume(&mut self, amt: usize) { - self.pos = cmp::min(self.pos + amt, self.cap); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<R> fmt::Debug for BufReader<R> -where - R: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("BufReader") - .field("reader", &self.inner) - .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<R: Seek> Seek for BufReader<R> { - /// Seek to an offset, in bytes, in the underlying reader. - /// - /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the - /// position the underlying reader would be at if the `BufReader<R>` had no - /// internal buffer. - /// - /// Seeking always discards the internal buffer, even if the seek position - /// would otherwise fall within it. This guarantees that calling - /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader - /// at the same position. - /// - /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`]. - /// - /// See [`std::io::Seek`] for more details. - /// - /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` - /// where `n` minus the internal buffer length overflows an `i64`, two - /// seeks will be performed instead of one. If the second seek returns - /// [`Err`], the underlying reader will be left at the same position it would - /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. - /// - /// [`std::io::Seek`]: Seek - fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { - let result: u64; - if let SeekFrom::Current(n) = pos { - let remainder = (self.cap - self.pos) as i64; - // it should be safe to assume that remainder fits within an i64 as the alternative - // means we managed to allocate 8 exbibytes and that's absurd. - // But it's not out of the realm of possibility for some weird underlying reader to - // support seeking by i64::MIN so we need to handle underflow when subtracting - // remainder. - if let Some(offset) = n.checked_sub(remainder) { - result = self.inner.seek(SeekFrom::Current(offset))?; - } else { - // seek backwards by our remainder, and then by the offset - self.inner.seek(SeekFrom::Current(-remainder))?; - self.discard_buffer(); - result = self.inner.seek(SeekFrom::Current(n))?; - } - } else { - // Seeking with Start/End doesn't care about our buffer length. - result = self.inner.seek(pos)?; - } - self.discard_buffer(); - Ok(result) - } - - /// Returns the current seek position from the start of the stream. - /// - /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` - /// but does not flush the internal buffer. Due to this optimization the - /// function does not guarantee that calling `.into_inner()` immediately - /// afterwards will yield the underlying reader at the same position. Use - /// [`BufReader::seek`] instead if you require that guarantee. - /// - /// # Panics - /// - /// This function will panic if the position of the inner reader is smaller - /// than the amount of buffered data. That can happen if the inner reader - /// has an incorrect implementation of [`Seek::stream_position`], or if the - /// position has gone out of sync due to calling [`Seek::seek`] directly on - /// the underlying reader. - /// - /// # Example - /// - /// ```no_run - /// #![feature(seek_convenience)] - /// use std::{ - /// io::{self, BufRead, BufReader, Seek}, - /// fs::File, - /// }; - /// - /// fn main() -> io::Result<()> { - /// let mut f = BufReader::new(File::open("foo.txt")?); - /// - /// let before = f.stream_position()?; - /// f.read_line(&mut String::new())?; - /// let after = f.stream_position()?; - /// - /// println!("The first line was {} bytes long", after - before); - /// Ok(()) - /// } - /// ``` - fn stream_position(&mut self) -> io::Result<u64> { - let remainder = (self.cap - self.pos) as u64; - self.inner.stream_position().map(|pos| { - pos.checked_sub(remainder).expect( - "overflow when subtracting remaining buffer size from inner stream position", - ) - }) - } -} - -/// Wraps a writer and buffers its output. -/// -/// It can be excessively inefficient to work directly with something that -/// implements [`Write`]. For example, every call to -/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A -/// `BufWriter<W>` keeps an in-memory buffer of data and writes it to an underlying -/// writer in large, infrequent batches. -/// -/// `BufWriter<W>` can improve the speed of programs that make *small* and -/// *repeated* write calls to the same file or network socket. It does not -/// help when writing very large amounts at once, or writing just one or a few -/// times. It also provides no advantage when writing to a destination that is -/// in memory, like a [`Vec`]<u8>`. -/// -/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though -/// dropping will attempt to flush the contents of the buffer, any errors -/// that happen in the process of dropping will be ignored. Calling [`flush`] -/// ensures that the buffer is empty and thus dropping will not even attempt -/// file operations. -/// -/// # Examples -/// -/// Let's write the numbers one through ten to a [`TcpStream`]: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::net::TcpStream; -/// -/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); -/// -/// for i in 0..10 { -/// stream.write(&[i+1]).unwrap(); -/// } -/// ``` -/// -/// Because we're not buffering, we write each one in turn, incurring the -/// overhead of a system call per byte written. We can fix this with a -/// `BufWriter<W>`: -/// -/// ```no_run -/// use std::io::prelude::*; -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// for i in 0..10 { -/// stream.write(&[i+1]).unwrap(); -/// } -/// stream.flush().unwrap(); -/// ``` -/// -/// By wrapping the stream with a `BufWriter<W>`, these ten writes are all grouped -/// together by the buffer and will all be written out in one system call when -/// the `stream` is flushed. -/// -/// [`TcpStream::write`]: Write::write -/// [`TcpStream`]: crate::net::TcpStream -/// [`flush`]: Write::flush -#[stable(feature = "rust1", since = "1.0.0")] -pub struct BufWriter<W: Write> { - inner: Option<W>, - buf: Vec<u8>, - // #30888: If the inner writer panics in a call to write, we don't want to - // write the buffered data a second time in BufWriter's destructor. This - // flag tells the Drop impl if it should skip the flush. - panicked: bool, -} - -/// An error returned by [`BufWriter::into_inner`] which combines an error that -/// happened while writing out the buffer, and the buffered writer object -/// which may be used to recover from the condition. -/// -/// # Examples -/// -/// ```no_run -/// use std::io::BufWriter; -/// use std::net::TcpStream; -/// -/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); -/// -/// // do stuff with the stream -/// -/// // we want to get our `TcpStream` back, so let's try: -/// -/// let stream = match stream.into_inner() { -/// Ok(s) => s, -/// Err(e) => { -/// // Here, e is an IntoInnerError -/// panic!("An error occurred"); -/// } -/// }; -/// ``` -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IntoInnerError<W>(W, Error); - -impl<W: Write> BufWriter<W> { - /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB, - /// but may change in the future. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: W) -> BufWriter<W> { - BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) - } - - /// Creates a new `BufWriter<W>` with the specified buffer capacity. - /// - /// # Examples - /// - /// Creating a buffer with a buffer of a hundred bytes. - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); - /// let mut buffer = BufWriter::with_capacity(100, stream); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> { - BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } - } - - /// Send data in our local buffer into the inner writer, looping as - /// necessary until either it's all been sent or an error occurs. - /// - /// Because all the data in the buffer has been reported to our owner as - /// "successfully written" (by returning nonzero success values from - /// `write`), any 0-length writes from `inner` must be reported as i/o - /// errors from this method. - fn flush_buf(&mut self) -> io::Result<()> { - /// Helper struct to ensure the buffer is updated after all the writes - /// are complete. It tracks the number of written bytes and drains them - /// all from the front of the buffer when dropped. - struct BufGuard<'a> { - buffer: &'a mut Vec<u8>, - written: usize, - } - - impl<'a> BufGuard<'a> { - fn new(buffer: &'a mut Vec<u8>) -> Self { - Self { buffer, written: 0 } - } - - /// The unwritten part of the buffer - fn remaining(&self) -> &[u8] { - &self.buffer[self.written..] - } - - /// Flag some bytes as removed from the front of the buffer - fn consume(&mut self, amt: usize) { - self.written += amt; - } - - /// true if all of the bytes have been written - fn done(&self) -> bool { - self.written >= self.buffer.len() - } - } - - impl Drop for BufGuard<'_> { - fn drop(&mut self) { - if self.written > 0 { - self.buffer.drain(..self.written); - } - } - } - - let mut guard = BufGuard::new(&mut self.buf); - let inner = self.inner.as_mut().unwrap(); - while !guard.done() { - self.panicked = true; - let r = inner.write(guard.remaining()); - self.panicked = false; - - match r { - Ok(0) => { - return Err(Error::new( - ErrorKind::WriteZero, - "failed to write the buffered data", - )); - } - Ok(n) => guard.consume(n), - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } - - /// Buffer some data without flushing it, regardless of the size of the - /// data. Writes as much as possible without exceeding capacity. Returns - /// the number of bytes written. - fn write_to_buf(&mut self, buf: &[u8]) -> usize { - let available = self.buf.capacity() - self.buf.len(); - let amt_to_buffer = available.min(buf.len()); - self.buf.extend_from_slice(&buf[..amt_to_buffer]); - amt_to_buffer - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_ref(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &W { - self.inner.as_ref().unwrap() - } - - /// Gets a mutable reference to the underlying writer. - /// - /// It is inadvisable to directly write to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // we can use reference just like buffer - /// let reference = buffer.get_mut(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut W { - self.inner.as_mut().unwrap() - } - - /// Returns a reference to the internally buffered data. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // See how many bytes are currently buffered - /// let bytes_buffered = buf_writer.buffer().len(); - /// ``` - #[stable(feature = "bufreader_buffer", since = "1.37.0")] - pub fn buffer(&self) -> &[u8] { - &self.buf - } - - /// Returns the number of bytes the internal buffer can hold without flushing. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // Check the capacity of the inner buffer - /// let capacity = buf_writer.capacity(); - /// // Calculate how many bytes can be written without flushing - /// let without_flush = capacity - buf_writer.buffer().len(); - /// ``` - #[stable(feature = "buffered_io_capacity", since = "1.46.0")] - pub fn capacity(&self) -> usize { - self.buf.capacity() - } - - /// Unwraps this `BufWriter<W>`, returning the underlying writer. - /// - /// The buffer is written out before returning the writer. - /// - /// # Errors - /// - /// An [`Err`] will be returned if an error occurs while flushing the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // unwrap the TcpStream and flush the buffer - /// let stream = buffer.into_inner().unwrap(); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> { - match self.flush_buf() { - Err(e) => Err(IntoInnerError(self, e)), - Ok(()) => Ok(self.inner.take().unwrap()), - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> Write for BufWriter<W> { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - if self.buf.len() + buf.len() > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if buf.len() >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write(buf); - self.panicked = false; - r - } else { - self.buf.extend_from_slice(buf); - Ok(buf.len()) - } - } - - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - // Normally, `write_all` just calls `write` in a loop. We can do better - // by calling `self.get_mut().write_all()` directly, which avoids - // round trips through the buffer in the event of a series of partial - // writes in some circumstances. - if self.buf.len() + buf.len() > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if buf.len() >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write_all(buf); - self.panicked = false; - r - } else { - self.buf.extend_from_slice(buf); - Ok(()) - } - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); - if self.buf.len() + total_len > self.buf.capacity() { - self.flush_buf()?; - } - // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 - if total_len >= self.buf.capacity() { - self.panicked = true; - let r = self.get_mut().write_vectored(bufs); - self.panicked = false; - r - } else { - bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); - Ok(total_len) - } - } - - fn is_write_vectored(&self) -> bool { - self.get_ref().is_write_vectored() - } - - fn flush(&mut self) -> io::Result<()> { - self.flush_buf().and_then(|()| self.get_mut().flush()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> fmt::Debug for BufWriter<W> -where - W: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("BufWriter") - .field("writer", &self.inner.as_ref().unwrap()) - .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) - .finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write + Seek> Seek for BufWriter<W> { - /// Seek to the offset, in bytes, in the underlying writer. - /// - /// Seeking always writes out the internal buffer before seeking. - fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { - self.flush_buf()?; - self.get_mut().seek(pos) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> Drop for BufWriter<W> { - fn drop(&mut self) { - if self.inner.is_some() && !self.panicked { - // dtors should not panic, so we ignore a failed flush - let _r = self.flush_buf(); - } - } -} - -impl<W> IntoInnerError<W> { - /// Returns the error which caused the call to [`BufWriter::into_inner()`] - /// to fail. - /// - /// This error was returned when attempting to write the internal buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's log the inner error. - /// // - /// // We'll just 'log' to stdout for this example. - /// println!("{}", e.error()); - /// - /// panic!("An unexpected error occurred."); - /// } - /// }; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn error(&self) -> &Error { - &self.1 - } - - /// Returns the buffered writer instance which generated the error. - /// - /// The returned object can be used for error recovery, such as - /// re-inspecting the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::io::BufWriter; - /// use std::net::TcpStream; - /// - /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); - /// - /// // do stuff with the stream - /// - /// // we want to get our `TcpStream` back, so let's try: - /// - /// let stream = match stream.into_inner() { - /// Ok(s) => s, - /// Err(e) => { - /// // Here, e is an IntoInnerError, let's re-examine the buffer: - /// let buffer = e.into_inner(); - /// - /// // do stuff to try to recover - /// - /// // afterwards, let's just return the stream - /// buffer.into_inner().unwrap() - /// } - /// }; - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> W { - self.0 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W> From<IntoInnerError<W>> for Error { - fn from(iie: IntoInnerError<W>) -> Error { - iie.1 - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> { - #[allow(deprecated, deprecated_in_future)] - fn description(&self) -> &str { - error::Error::description(self.error()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W> fmt::Display for IntoInnerError<W> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.error().fmt(f) - } -} - -/// Private helper struct for implementing the line-buffered writing logic. -/// This shim temporarily wraps a BufWriter, and uses its internals to -/// implement a line-buffered writer (specifically by using the internal -/// methods like write_to_buf and flush_buf). In this way, a more -/// efficient abstraction can be created than one that only had access to -/// `write` and `flush`, without needlessly duplicating a lot of the -/// implementation details of BufWriter. This also allows existing -/// `BufWriters` to be temporarily given line-buffering logic; this is what -/// enables Stdout to be alternately in line-buffered or block-buffered mode. -#[derive(Debug)] -pub(super) struct LineWriterShim<'a, W: Write> { - buffer: &'a mut BufWriter<W>, -} - -impl<'a, W: Write> LineWriterShim<'a, W> { - pub fn new(buffer: &'a mut BufWriter<W>) -> Self { - Self { buffer } - } - - /// Get a mutable reference to the inner writer (that is, the writer - /// wrapped by the BufWriter). Be careful with this writer, as writes to - /// it will bypass the buffer. - fn inner_mut(&mut self) -> &mut W { - self.buffer.get_mut() - } - - /// Get the content currently buffered in self.buffer - fn buffered(&self) -> &[u8] { - self.buffer.buffer() - } - - /// Flush the buffer iff the last byte is a newline (indicating that an - /// earlier write only succeeded partially, and we want to retry flushing - /// the buffered line before continuing with a subsequent write) - fn flush_if_completed_line(&mut self) -> io::Result<()> { - match self.buffered().last().copied() { - Some(b'\n') => self.buffer.flush_buf(), - _ => Ok(()), - } - } -} - -impl<'a, W: Write> Write for LineWriterShim<'a, W> { - /// Write some data into this BufReader with line buffering. This means - /// that, if any newlines are present in the data, the data up to the last - /// newline is sent directly to the underlying writer, and data after it - /// is buffered. Returns the number of bytes written. - /// - /// This function operates on a "best effort basis"; in keeping with the - /// convention of `Write::write`, it makes at most one attempt to write - /// new data to the underlying writer. If that write only reports a partial - /// success, the remaining data will be buffered. - /// - /// Because this function attempts to send completed lines to the underlying - /// writer, it will also flush the existing buffer if it ends with a - /// newline, even if the incoming data does not contain any newlines. - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let newline_idx = match memchr::memrchr(b'\n', buf) { - // If there are no new newlines (that is, if this write is less than - // one line), just do a regular buffered write (which may flush if - // we exceed the inner buffer's size) - None => { - self.flush_if_completed_line()?; - return self.buffer.write(buf); - } - // Otherwise, arrange for the lines to be written directly to the - // inner writer. - Some(newline_idx) => newline_idx + 1, - }; - - // Flush existing content to prepare for our write. We have to do this - // before attempting to write `buf` in order to maintain consistency; - // if we add `buf` to the buffer then try to flush it all at once, - // we're obligated to return Ok(), which would mean suppressing any - // errors that occur during flush. - self.buffer.flush_buf()?; - - // This is what we're going to try to write directly to the inner - // writer. The rest will be buffered, if nothing goes wrong. - let lines = &buf[..newline_idx]; - - // Write `lines` directly to the inner writer. In keeping with the - // `write` convention, make at most one attempt to add new (unbuffered) - // data. Because this write doesn't touch the BufWriter state directly, - // and the buffer is known to be empty, we don't need to worry about - // self.buffer.panicked here. - let flushed = self.inner_mut().write(lines)?; - - // If buffer returns Ok(0), propagate that to the caller without - // doing additional buffering; otherwise we're just guaranteeing - // an "ErrorKind::WriteZero" later. - if flushed == 0 { - return Ok(0); - } - - // Now that the write has succeeded, buffer the rest (or as much of - // the rest as possible). If there were any unwritten newlines, we - // only buffer out to the last unwritten newline that fits in the - // buffer; this helps prevent flushing partial lines on subsequent - // calls to LineWriterShim::write. - - // Handle the cases in order of most-common to least-common, under - // the presumption that most writes succeed in totality, and that most - // writes are smaller than the buffer. - // - Is this a partial line (ie, no newlines left in the unwritten tail) - // - If not, does the data out to the last unwritten newline fit in - // the buffer? - // - If not, scan for the last newline that *does* fit in the buffer - let tail = if flushed >= newline_idx { - &buf[flushed..] - } else if newline_idx - flushed <= self.buffer.capacity() { - &buf[flushed..newline_idx] - } else { - let scan_area = &buf[flushed..]; - let scan_area = &scan_area[..self.buffer.capacity()]; - match memchr::memrchr(b'\n', scan_area) { - Some(newline_idx) => &scan_area[..newline_idx + 1], - None => scan_area, - } - }; - - let buffered = self.buffer.write_to_buf(tail); - Ok(flushed + buffered) - } - - fn flush(&mut self) -> io::Result<()> { - self.buffer.flush() - } - - /// Write some vectored data into this BufReader with line buffering. This - /// means that, if any newlines are present in the data, the data up to - /// and including the buffer containing the last newline is sent directly - /// to the inner writer, and the data after it is buffered. Returns the - /// number of bytes written. - /// - /// This function operates on a "best effort basis"; in keeping with the - /// convention of `Write::write`, it makes at most one attempt to write - /// new data to the underlying writer. - /// - /// Because this function attempts to send completed lines to the underlying - /// writer, it will also flush the existing buffer if it contains any - /// newlines. - /// - /// Because sorting through an array of `IoSlice` can be a bit convoluted, - /// This method differs from write in the following ways: - /// - /// - It attempts to write the full content of all the buffers up to and - /// including the one containing the last newline. This means that it - /// may attempt to write a partial line, that buffer has data past the - /// newline. - /// - If the write only reports partial success, it does not attempt to - /// find the precise location of the written bytes and buffer the rest. - /// - /// If the underlying vector doesn't support vectored writing, we instead - /// simply write the first non-empty buffer with `write`. This way, we - /// get the benefits of more granular partial-line handling without losing - /// anything in efficiency - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - // If there's no specialized behavior for write_vectored, just use - // write. This has the benefit of more granular partial-line handling. - if !self.is_write_vectored() { - return match bufs.iter().find(|buf| !buf.is_empty()) { - Some(buf) => self.write(buf), - None => Ok(0), - }; - } - - // Find the buffer containing the last newline - let last_newline_buf_idx = bufs - .iter() - .enumerate() - .rev() - .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); - - // If there are no new newlines (that is, if this write is less than - // one line), just do a regular buffered write - let last_newline_buf_idx = match last_newline_buf_idx { - // No newlines; just do a normal buffered write - None => { - self.flush_if_completed_line()?; - return self.buffer.write_vectored(bufs); - } - Some(i) => i, - }; - - // Flush existing content to prepare for our write - self.buffer.flush_buf()?; - - // This is what we're going to try to write directly to the inner - // writer. The rest will be buffered, if nothing goes wrong. - let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); - - // Write `lines` directly to the inner writer. In keeping with the - // `write` convention, make at most one attempt to add new (unbuffered) - // data. Because this write doesn't touch the BufWriter state directly, - // and the buffer is known to be empty, we don't need to worry about - // self.panicked here. - let flushed = self.inner_mut().write_vectored(lines)?; - - // If inner returns Ok(0), propagate that to the caller without - // doing additional buffering; otherwise we're just guaranteeing - // an "ErrorKind::WriteZero" later. - if flushed == 0 { - return Ok(0); - } - - // Don't try to reconstruct the exact amount written; just bail - // in the event of a partial write - let lines_len = lines.iter().map(|buf| buf.len()).sum(); - if flushed < lines_len { - return Ok(flushed); - } - - // Now that the write has succeeded, buffer the rest (or as much of the - // rest as possible) - let buffered: usize = tail - .iter() - .filter(|buf| !buf.is_empty()) - .map(|buf| self.buffer.write_to_buf(buf)) - .take_while(|&n| n > 0) - .sum(); - - Ok(flushed + buffered) - } - - fn is_write_vectored(&self) -> bool { - self.buffer.is_write_vectored() - } - - /// Write some data into this BufReader with line buffering. This means - /// that, if any newlines are present in the data, the data up to the last - /// newline is sent directly to the underlying writer, and data after it - /// is buffered. - /// - /// Because this function attempts to send completed lines to the underlying - /// writer, it will also flush the existing buffer if it contains any - /// newlines, even if the incoming data does not contain any newlines. - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - match memchr::memrchr(b'\n', buf) { - // If there are no new newlines (that is, if this write is less than - // one line), just do a regular buffered write (which may flush if - // we exceed the inner buffer's size) - None => { - self.flush_if_completed_line()?; - self.buffer.write_all(buf) - } - Some(newline_idx) => { - let (lines, tail) = buf.split_at(newline_idx + 1); - - if self.buffered().is_empty() { - self.inner_mut().write_all(lines)?; - } else { - // If there is any buffered data, we add the incoming lines - // to that buffer before flushing, which saves us at least - // one write call. We can't really do this with `write`, - // since we can't do this *and* not suppress errors *and* - // report a consistent state to the caller in a return - // value, but here in write_all it's fine. - self.buffer.write_all(lines)?; - self.buffer.flush_buf()?; - } - - self.buffer.write_all(tail) - } - } - } -} - -/// Wraps a writer and buffers output to it, flushing whenever a newline -/// (`0x0a`, `'\n'`) is detected. -/// -/// The [`BufWriter`] struct wraps a writer and buffers its output. -/// But it only does this batched write when it goes out of scope, or when the -/// internal buffer is full. Sometimes, you'd prefer to write each line as it's -/// completed, rather than the entire buffer at once. Enter `LineWriter`. It -/// does exactly that. -/// -/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the -/// `LineWriter` goes out of scope or when its internal buffer is full. -/// -/// If there's still a partial line in the buffer when the `LineWriter` is -/// dropped, it will flush those contents. -/// -/// # Examples -/// -/// We can use `LineWriter` to write one line at a time, significantly -/// reducing the number of actual writes to the file. -/// -/// ```no_run -/// use std::fs::{self, File}; -/// use std::io::prelude::*; -/// use std::io::LineWriter; -/// -/// fn main() -> std::io::Result<()> { -/// let road_not_taken = b"I shall be telling this with a sigh -/// Somewhere ages and ages hence: -/// Two roads diverged in a wood, and I - -/// I took the one less traveled by, -/// And that has made all the difference."; -/// -/// let file = File::create("poem.txt")?; -/// let mut file = LineWriter::new(file); -/// -/// file.write_all(b"I shall be telling this with a sigh")?; -/// -/// // No bytes are written until a newline is encountered (or -/// // the internal buffer is filled). -/// assert_eq!(fs::read_to_string("poem.txt")?, ""); -/// file.write_all(b"\n")?; -/// assert_eq!( -/// fs::read_to_string("poem.txt")?, -/// "I shall be telling this with a sigh\n", -/// ); -/// -/// // Write the rest of the poem. -/// file.write_all(b"Somewhere ages and ages hence: -/// Two roads diverged in a wood, and I - -/// I took the one less traveled by, -/// And that has made all the difference.")?; -/// -/// // The last line of the poem doesn't end in a newline, so -/// // we have to flush or drop the `LineWriter` to finish -/// // writing. -/// file.flush()?; -/// -/// // Confirm the whole poem was written. -/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); -/// Ok(()) -/// } -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub struct LineWriter<W: Write> { - inner: BufWriter<W>, -} - -impl<W: Write> LineWriter<W> { - /// Creates a new `LineWriter`. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(inner: W) -> LineWriter<W> { - // Lines typically aren't that long, don't use a giant buffer - LineWriter::with_capacity(1024, inner) - } - - /// Creates a new `LineWriter` with a specified capacity for the internal - /// buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::with_capacity(100, file); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> { - LineWriter { inner: BufWriter::with_capacity(capacity, inner) } - } - - /// Gets a reference to the underlying writer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let file = LineWriter::new(file); - /// - /// let reference = file.get_ref(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_ref(&self) -> &W { - self.inner.get_ref() - } - - /// Gets a mutable reference to the underlying writer. - /// - /// Caution must be taken when calling methods on the mutable reference - /// returned as extra writes could corrupt the output stream. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// let mut file = LineWriter::new(file); - /// - /// // we can use reference just like file - /// let reference = file.get_mut(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn get_mut(&mut self) -> &mut W { - self.inner.get_mut() - } - - /// Unwraps this `LineWriter`, returning the underlying writer. - /// - /// The internal buffer is written out before returning the writer. - /// - /// # Errors - /// - /// An [`Err`] will be returned if an error occurs while flushing the buffer. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io::LineWriter; - /// - /// fn main() -> std::io::Result<()> { - /// let file = File::create("poem.txt")?; - /// - /// let writer: LineWriter<File> = LineWriter::new(file); - /// - /// let file: File = writer.into_inner()?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> { - self.inner - .into_inner() - .map_err(|IntoInnerError(buf, e)| IntoInnerError(LineWriter { inner: buf }, e)) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> Write for LineWriter<W> { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - LineWriterShim::new(&mut self.inner).write(buf) - } - - fn flush(&mut self) -> io::Result<()> { - self.inner.flush() - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - LineWriterShim::new(&mut self.inner).write_vectored(bufs) - } - - fn is_write_vectored(&self) -> bool { - self.inner.is_write_vectored() - } - - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - LineWriterShim::new(&mut self.inner).write_all(buf) - } - - fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { - LineWriterShim::new(&mut self.inner).write_all_vectored(bufs) - } - - fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { - LineWriterShim::new(&mut self.inner).write_fmt(fmt) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<W: Write> fmt::Debug for LineWriter<W> -where - W: fmt::Debug, -{ - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt.debug_struct("LineWriter") - .field("writer", &self.inner.inner) - .field( - "buffer", - &format_args!("{}/{}", self.inner.buf.len(), self.inner.buf.capacity()), - ) - .finish() - } -} diff --git a/library/std/src/io/buffered/bufreader.rs b/library/std/src/io/buffered/bufreader.rs new file mode 100644 index 00000000000..8fe29f08a7b --- /dev/null +++ b/library/std/src/io/buffered/bufreader.rs @@ -0,0 +1,423 @@ +use crate::cmp; +use crate::fmt; +use crate::io::{self, BufRead, Initializer, IoSliceMut, Read, Seek, SeekFrom, DEFAULT_BUF_SIZE}; + +/// The `BufReader<R>` struct adds buffering to any reader. +/// +/// It can be excessively inefficient to work directly with a [`Read`] instance. +/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`] +/// results in a system call. A `BufReader<R>` performs large, infrequent reads on +/// the underlying [`Read`] and maintains an in-memory buffer of the results. +/// +/// `BufReader<R>` can improve the speed of programs that make *small* and +/// *repeated* read calls to the same file or network socket. It does not +/// help when reading very large amounts at once, or reading just one or a few +/// times. It also provides no advantage when reading from a source that is +/// already in memory, like a [`Vec`]`<u8>`. +/// +/// When the `BufReader<R>` is dropped, the contents of its buffer will be +/// discarded. Creating multiple instances of a `BufReader<R>` on the same +/// stream can cause data loss. Reading from the underlying reader after +/// unwrapping the `BufReader<R>` with [`BufReader::into_inner`] can also cause +/// data loss. +/// +/// [`TcpStream::read`]: Read::read +/// [`TcpStream`]: crate::net::TcpStream +/// +/// # Examples +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufReader; +/// use std::fs::File; +/// +/// fn main() -> std::io::Result<()> { +/// let f = File::open("log.txt")?; +/// let mut reader = BufReader::new(f); +/// +/// let mut line = String::new(); +/// let len = reader.read_line(&mut line)?; +/// println!("First line is {} bytes long", len); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BufReader<R> { + inner: R, + buf: Box<[u8]>, + pos: usize, + cap: usize, +} + +impl<R: Read> BufReader<R> { + /// Creates a new `BufReader<R>` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::new(f); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: R) -> BufReader<R> { + BufReader::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufReader<R>` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with ten bytes of capacity: + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let reader = BufReader::with_capacity(10, f); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize, inner: R) -> BufReader<R> { + unsafe { + let mut buffer = Vec::with_capacity(capacity); + buffer.set_len(capacity); + inner.initializer().initialize(&mut buffer); + BufReader { inner, buf: buffer.into_boxed_slice(), pos: 0, cap: 0 } + } + } +} + +impl<R> BufReader<R> { + /// Gets a reference to the underlying reader. + /// + /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); + /// + /// let f2 = reader.get_ref(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &R { + &self.inner + } + + /// Gets a mutable reference to the underlying reader. + /// + /// It is inadvisable to directly read from the underlying reader. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let mut reader = BufReader::new(f1); + /// + /// let f2 = reader.get_mut(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner + } + + /// Returns a reference to the internally buffered data. + /// + /// Unlike [`fill_buf`], this will not attempt to fill the buffer if it is empty. + /// + /// [`fill_buf`]: BufRead::fill_buf + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{BufReader, BufRead}; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let mut reader = BufReader::new(f); + /// assert!(reader.buffer().is_empty()); + /// + /// if reader.fill_buf()?.len() > 0 { + /// assert!(!reader.buffer().is_empty()); + /// } + /// Ok(()) + /// } + /// ``` + #[stable(feature = "bufreader_buffer", since = "1.37.0")] + pub fn buffer(&self) -> &[u8] { + &self.buf[self.pos..self.cap] + } + + /// Returns the number of bytes the internal buffer can hold at once. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::{BufReader, BufRead}; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f = File::open("log.txt")?; + /// let mut reader = BufReader::new(f); + /// + /// let capacity = reader.capacity(); + /// let buffer = reader.fill_buf()?; + /// assert!(buffer.len() <= capacity); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "buffered_io_capacity", since = "1.46.0")] + pub fn capacity(&self) -> usize { + self.buf.len() + } + + /// Unwraps this `BufReader<R>`, returning the underlying reader. + /// + /// Note that any leftover data in the internal buffer is lost. Therefore, + /// a following read from the underlying reader may lead to data loss. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufReader; + /// use std::fs::File; + /// + /// fn main() -> std::io::Result<()> { + /// let f1 = File::open("log.txt")?; + /// let reader = BufReader::new(f1); + /// + /// let f2 = reader.into_inner(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> R { + self.inner + } + + /// Invalidates all data in the internal buffer. + #[inline] + fn discard_buffer(&mut self) { + self.pos = 0; + self.cap = 0; + } +} + +impl<R: Seek> BufReader<R> { + /// Seeks relative to the current position. If the new position lies within the buffer, + /// the buffer will not be flushed, allowing for more efficient seeks. + /// This method does not return the location of the underlying reader, so the caller + /// must track this information themselves if it is required. + #[unstable(feature = "bufreader_seek_relative", issue = "31100")] + pub fn seek_relative(&mut self, offset: i64) -> io::Result<()> { + let pos = self.pos as u64; + if offset < 0 { + if let Some(new_pos) = pos.checked_sub((-offset) as u64) { + self.pos = new_pos as usize; + return Ok(()); + } + } else { + if let Some(new_pos) = pos.checked_add(offset as u64) { + if new_pos <= self.cap as u64 { + self.pos = new_pos as usize; + return Ok(()); + } + } + } + self.seek(SeekFrom::Current(offset)).map(drop) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<R: Read> Read for BufReader<R> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + // If we don't have any buffered data and we're doing a massive read + // (larger than our internal buffer), bypass our internal buffer + // entirely. + if self.pos == self.cap && buf.len() >= self.buf.len() { + self.discard_buffer(); + return self.inner.read(buf); + } + let nread = { + let mut rem = self.fill_buf()?; + rem.read(buf)? + }; + self.consume(nread); + Ok(nread) + } + + fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); + if self.pos == self.cap && total_len >= self.buf.len() { + self.discard_buffer(); + return self.inner.read_vectored(bufs); + } + let nread = { + let mut rem = self.fill_buf()?; + rem.read_vectored(bufs)? + }; + self.consume(nread); + Ok(nread) + } + + fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + + // we can't skip unconditionally because of the large buffer case in read. + unsafe fn initializer(&self) -> Initializer { + self.inner.initializer() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<R: Read> BufRead for BufReader<R> { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + // If we've reached the end of our internal buffer then we need to fetch + // some more data from the underlying reader. + // Branch using `>=` instead of the more correct `==` + // to tell the compiler that the pos..cap slice is always valid. + if self.pos >= self.cap { + debug_assert!(self.pos == self.cap); + self.cap = self.inner.read(&mut self.buf)?; + self.pos = 0; + } + Ok(&self.buf[self.pos..self.cap]) + } + + fn consume(&mut self, amt: usize) { + self.pos = cmp::min(self.pos + amt, self.cap); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<R> fmt::Debug for BufReader<R> +where + R: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("BufReader") + .field("reader", &self.inner) + .field("buffer", &format_args!("{}/{}", self.cap - self.pos, self.buf.len())) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<R: Seek> Seek for BufReader<R> { + /// Seek to an offset, in bytes, in the underlying reader. + /// + /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the + /// position the underlying reader would be at if the `BufReader<R>` had no + /// internal buffer. + /// + /// Seeking always discards the internal buffer, even if the seek position + /// would otherwise fall within it. This guarantees that calling + /// [`BufReader::into_inner()`] immediately after a seek yields the underlying reader + /// at the same position. + /// + /// To seek without discarding the internal buffer, use [`BufReader::seek_relative`]. + /// + /// See [`std::io::Seek`] for more details. + /// + /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)` + /// where `n` minus the internal buffer length overflows an `i64`, two + /// seeks will be performed instead of one. If the second seek returns + /// [`Err`], the underlying reader will be left at the same position it would + /// have if you called `seek` with [`SeekFrom::Current`]`(0)`. + /// + /// [`std::io::Seek`]: Seek + fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { + let result: u64; + if let SeekFrom::Current(n) = pos { + let remainder = (self.cap - self.pos) as i64; + // it should be safe to assume that remainder fits within an i64 as the alternative + // means we managed to allocate 8 exbibytes and that's absurd. + // But it's not out of the realm of possibility for some weird underlying reader to + // support seeking by i64::MIN so we need to handle underflow when subtracting + // remainder. + if let Some(offset) = n.checked_sub(remainder) { + result = self.inner.seek(SeekFrom::Current(offset))?; + } else { + // seek backwards by our remainder, and then by the offset + self.inner.seek(SeekFrom::Current(-remainder))?; + self.discard_buffer(); + result = self.inner.seek(SeekFrom::Current(n))?; + } + } else { + // Seeking with Start/End doesn't care about our buffer length. + result = self.inner.seek(pos)?; + } + self.discard_buffer(); + Ok(result) + } + + /// Returns the current seek position from the start of the stream. + /// + /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` + /// but does not flush the internal buffer. Due to this optimization the + /// function does not guarantee that calling `.into_inner()` immediately + /// afterwards will yield the underlying reader at the same position. Use + /// [`BufReader::seek`] instead if you require that guarantee. + /// + /// # Panics + /// + /// This function will panic if the position of the inner reader is smaller + /// than the amount of buffered data. That can happen if the inner reader + /// has an incorrect implementation of [`Seek::stream_position`], or if the + /// position has gone out of sync due to calling [`Seek::seek`] directly on + /// the underlying reader. + /// + /// # Example + /// + /// ```no_run + /// #![feature(seek_convenience)] + /// use std::{ + /// io::{self, BufRead, BufReader, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = BufReader::new(File::open("foo.txt")?); + /// + /// let before = f.stream_position()?; + /// f.read_line(&mut String::new())?; + /// let after = f.stream_position()?; + /// + /// println!("The first line was {} bytes long", after - before); + /// Ok(()) + /// } + /// ``` + fn stream_position(&mut self) -> io::Result<u64> { + let remainder = (self.cap - self.pos) as u64; + self.inner.stream_position().map(|pos| { + pos.checked_sub(remainder).expect( + "overflow when subtracting remaining buffer size from inner stream position", + ) + }) + } +} diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs new file mode 100644 index 00000000000..8ce795a05ed --- /dev/null +++ b/library/std/src/io/buffered/bufwriter.rs @@ -0,0 +1,387 @@ +use crate::fmt; +use crate::io::{ + self, Error, ErrorKind, IntoInnerError, IoSlice, Seek, SeekFrom, Write, DEFAULT_BUF_SIZE, +}; + +/// Wraps a writer and buffers its output. +/// +/// It can be excessively inefficient to work directly with something that +/// implements [`Write`]. For example, every call to +/// [`write`][`TcpStream::write`] on [`TcpStream`] results in a system call. A +/// `BufWriter<W>` keeps an in-memory buffer of data and writes it to an underlying +/// writer in large, infrequent batches. +/// +/// `BufWriter<W>` can improve the speed of programs that make *small* and +/// *repeated* write calls to the same file or network socket. It does not +/// help when writing very large amounts at once, or writing just one or a few +/// times. It also provides no advantage when writing to a destination that is +/// in memory, like a [`Vec`]<u8>`. +/// +/// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though +/// dropping will attempt to flush the contents of the buffer, any errors +/// that happen in the process of dropping will be ignored. Calling [`flush`] +/// ensures that the buffer is empty and thus dropping will not even attempt +/// file operations. +/// +/// # Examples +/// +/// Let's write the numbers one through ten to a [`TcpStream`]: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::net::TcpStream; +/// +/// let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap(); +/// +/// for i in 0..10 { +/// stream.write(&[i+1]).unwrap(); +/// } +/// ``` +/// +/// Because we're not buffering, we write each one in turn, incurring the +/// overhead of a system call per byte written. We can fix this with a +/// `BufWriter<W>`: +/// +/// ```no_run +/// use std::io::prelude::*; +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// for i in 0..10 { +/// stream.write(&[i+1]).unwrap(); +/// } +/// stream.flush().unwrap(); +/// ``` +/// +/// By wrapping the stream with a `BufWriter<W>`, these ten writes are all grouped +/// together by the buffer and will all be written out in one system call when +/// the `stream` is flushed. +/// +/// [`TcpStream::write`]: Write::write +/// [`TcpStream`]: crate::net::TcpStream +/// [`flush`]: Write::flush +#[stable(feature = "rust1", since = "1.0.0")] +pub struct BufWriter<W: Write> { + inner: Option<W>, + buf: Vec<u8>, + // #30888: If the inner writer panics in a call to write, we don't want to + // write the buffered data a second time in BufWriter's destructor. This + // flag tells the Drop impl if it should skip the flush. + panicked: bool, +} + +impl<W: Write> BufWriter<W> { + /// Creates a new `BufWriter<W>` with a default buffer capacity. The default is currently 8 KB, + /// but may change in the future. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: W) -> BufWriter<W> { + BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner) + } + + /// Creates a new `BufWriter<W>` with the specified buffer capacity. + /// + /// # Examples + /// + /// Creating a buffer with a buffer of a hundred bytes. + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let stream = TcpStream::connect("127.0.0.1:34254").unwrap(); + /// let mut buffer = BufWriter::with_capacity(100, stream); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize, inner: W) -> BufWriter<W> { + BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } + } + + /// Send data in our local buffer into the inner writer, looping as + /// necessary until either it's all been sent or an error occurs. + /// + /// Because all the data in the buffer has been reported to our owner as + /// "successfully written" (by returning nonzero success values from + /// `write`), any 0-length writes from `inner` must be reported as i/o + /// errors from this method. + pub(super) fn flush_buf(&mut self) -> io::Result<()> { + /// Helper struct to ensure the buffer is updated after all the writes + /// are complete. It tracks the number of written bytes and drains them + /// all from the front of the buffer when dropped. + struct BufGuard<'a> { + buffer: &'a mut Vec<u8>, + written: usize, + } + + impl<'a> BufGuard<'a> { + fn new(buffer: &'a mut Vec<u8>) -> Self { + Self { buffer, written: 0 } + } + + /// The unwritten part of the buffer + fn remaining(&self) -> &[u8] { + &self.buffer[self.written..] + } + + /// Flag some bytes as removed from the front of the buffer + fn consume(&mut self, amt: usize) { + self.written += amt; + } + + /// true if all of the bytes have been written + fn done(&self) -> bool { + self.written >= self.buffer.len() + } + } + + impl Drop for BufGuard<'_> { + fn drop(&mut self) { + if self.written > 0 { + self.buffer.drain(..self.written); + } + } + } + + let mut guard = BufGuard::new(&mut self.buf); + let inner = self.inner.as_mut().unwrap(); + while !guard.done() { + self.panicked = true; + let r = inner.write(guard.remaining()); + self.panicked = false; + + match r { + Ok(0) => { + return Err(Error::new( + ErrorKind::WriteZero, + "failed to write the buffered data", + )); + } + Ok(n) => guard.consume(n), + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + Ok(()) + } + + /// Buffer some data without flushing it, regardless of the size of the + /// data. Writes as much as possible without exceeding capacity. Returns + /// the number of bytes written. + pub(super) fn write_to_buf(&mut self, buf: &[u8]) -> usize { + let available = self.buf.capacity() - self.buf.len(); + let amt_to_buffer = available.min(buf.len()); + self.buf.extend_from_slice(&buf[..amt_to_buffer]); + amt_to_buffer + } + + /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_ref(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { + self.inner.as_ref().unwrap() + } + + /// Gets a mutable reference to the underlying writer. + /// + /// It is inadvisable to directly write to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // we can use reference just like buffer + /// let reference = buffer.get_mut(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut W { + self.inner.as_mut().unwrap() + } + + /// Returns a reference to the internally buffered data. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // See how many bytes are currently buffered + /// let bytes_buffered = buf_writer.buffer().len(); + /// ``` + #[stable(feature = "bufreader_buffer", since = "1.37.0")] + pub fn buffer(&self) -> &[u8] { + &self.buf + } + + /// Returns the number of bytes the internal buffer can hold without flushing. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let buf_writer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // Check the capacity of the inner buffer + /// let capacity = buf_writer.capacity(); + /// // Calculate how many bytes can be written without flushing + /// let without_flush = capacity - buf_writer.buffer().len(); + /// ``` + #[stable(feature = "buffered_io_capacity", since = "1.46.0")] + pub fn capacity(&self) -> usize { + self.buf.capacity() + } + + /// Unwraps this `BufWriter<W>`, returning the underlying writer. + /// + /// The buffer is written out before returning the writer. + /// + /// # Errors + /// + /// An [`Err`] will be returned if an error occurs while flushing the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut buffer = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // unwrap the TcpStream and flush the buffer + /// let stream = buffer.into_inner().unwrap(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> { + match self.flush_buf() { + Err(e) => Err(IntoInnerError::new(self, e)), + Ok(()) => Ok(self.inner.take().unwrap()), + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> Write for BufWriter<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write(buf); + self.panicked = false; + r + } else { + self.buf.extend_from_slice(buf); + Ok(buf.len()) + } + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + // Normally, `write_all` just calls `write` in a loop. We can do better + // by calling `self.get_mut().write_all()` directly, which avoids + // round trips through the buffer in the event of a series of partial + // writes in some circumstances. + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_all(buf); + self.panicked = false; + r + } else { + self.buf.extend_from_slice(buf); + Ok(()) + } + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + let total_len = bufs.iter().map(|b| b.len()).sum::<usize>(); + if self.buf.len() + total_len > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if total_len >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_vectored(bufs); + self.panicked = false; + r + } else { + bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); + Ok(total_len) + } + } + + fn is_write_vectored(&self) -> bool { + self.get_ref().is_write_vectored() + } + + fn flush(&mut self) -> io::Result<()> { + self.flush_buf().and_then(|()| self.get_mut().flush()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> fmt::Debug for BufWriter<W> +where + W: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("BufWriter") + .field("writer", &self.inner.as_ref().unwrap()) + .field("buffer", &format_args!("{}/{}", self.buf.len(), self.buf.capacity())) + .finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write + Seek> Seek for BufWriter<W> { + /// Seek to the offset, in bytes, in the underlying writer. + /// + /// Seeking always writes out the internal buffer before seeking. + fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { + self.flush_buf()?; + self.get_mut().seek(pos) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> Drop for BufWriter<W> { + fn drop(&mut self) { + if self.inner.is_some() && !self.panicked { + // dtors should not panic, so we ignore a failed flush + let _r = self.flush_buf(); + } + } +} diff --git a/library/std/src/io/buffered/linewriter.rs b/library/std/src/io/buffered/linewriter.rs new file mode 100644 index 00000000000..502c6e3c6c0 --- /dev/null +++ b/library/std/src/io/buffered/linewriter.rs @@ -0,0 +1,232 @@ +use crate::fmt; +use crate::io::{self, buffered::LineWriterShim, BufWriter, IntoInnerError, IoSlice, Write}; + +/// Wraps a writer and buffers output to it, flushing whenever a newline +/// (`0x0a`, `'\n'`) is detected. +/// +/// The [`BufWriter`] struct wraps a writer and buffers its output. +/// But it only does this batched write when it goes out of scope, or when the +/// internal buffer is full. Sometimes, you'd prefer to write each line as it's +/// completed, rather than the entire buffer at once. Enter `LineWriter`. It +/// does exactly that. +/// +/// Like [`BufWriter`], a `LineWriter`’s buffer will also be flushed when the +/// `LineWriter` goes out of scope or when its internal buffer is full. +/// +/// If there's still a partial line in the buffer when the `LineWriter` is +/// dropped, it will flush those contents. +/// +/// # Examples +/// +/// We can use `LineWriter` to write one line at a time, significantly +/// reducing the number of actual writes to the file. +/// +/// ```no_run +/// use std::fs::{self, File}; +/// use std::io::prelude::*; +/// use std::io::LineWriter; +/// +/// fn main() -> std::io::Result<()> { +/// let road_not_taken = b"I shall be telling this with a sigh +/// Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference."; +/// +/// let file = File::create("poem.txt")?; +/// let mut file = LineWriter::new(file); +/// +/// file.write_all(b"I shall be telling this with a sigh")?; +/// +/// // No bytes are written until a newline is encountered (or +/// // the internal buffer is filled). +/// assert_eq!(fs::read_to_string("poem.txt")?, ""); +/// file.write_all(b"\n")?; +/// assert_eq!( +/// fs::read_to_string("poem.txt")?, +/// "I shall be telling this with a sigh\n", +/// ); +/// +/// // Write the rest of the poem. +/// file.write_all(b"Somewhere ages and ages hence: +/// Two roads diverged in a wood, and I - +/// I took the one less traveled by, +/// And that has made all the difference.")?; +/// +/// // The last line of the poem doesn't end in a newline, so +/// // we have to flush or drop the `LineWriter` to finish +/// // writing. +/// file.flush()?; +/// +/// // Confirm the whole poem was written. +/// assert_eq!(fs::read("poem.txt")?, &road_not_taken[..]); +/// Ok(()) +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub struct LineWriter<W: Write> { + inner: BufWriter<W>, +} + +impl<W: Write> LineWriter<W> { + /// Creates a new `LineWriter`. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(inner: W) -> LineWriter<W> { + // Lines typically aren't that long, don't use a giant buffer + LineWriter::with_capacity(1024, inner) + } + + /// Creates a new `LineWriter` with a specified capacity for the internal + /// buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::with_capacity(100, file); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn with_capacity(capacity: usize, inner: W) -> LineWriter<W> { + LineWriter { inner: BufWriter::with_capacity(capacity, inner) } + } + + /// Gets a reference to the underlying writer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let file = LineWriter::new(file); + /// + /// let reference = file.get_ref(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_ref(&self) -> &W { + self.inner.get_ref() + } + + /// Gets a mutable reference to the underlying writer. + /// + /// Caution must be taken when calling methods on the mutable reference + /// returned as extra writes could corrupt the output stream. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// let mut file = LineWriter::new(file); + /// + /// // we can use reference just like file + /// let reference = file.get_mut(); + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn get_mut(&mut self) -> &mut W { + self.inner.get_mut() + } + + /// Unwraps this `LineWriter`, returning the underlying writer. + /// + /// The internal buffer is written out before returning the writer. + /// + /// # Errors + /// + /// An [`Err`] will be returned if an error occurs while flushing the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::io::LineWriter; + /// + /// fn main() -> std::io::Result<()> { + /// let file = File::create("poem.txt")?; + /// + /// let writer: LineWriter<File> = LineWriter::new(file); + /// + /// let file: File = writer.into_inner()?; + /// Ok(()) + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> { + self.inner.into_inner().map_err(|err| err.new_wrapped(|inner| LineWriter { inner })) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> Write for LineWriter<W> { + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + LineWriterShim::new(&mut self.inner).write(buf) + } + + fn flush(&mut self) -> io::Result<()> { + self.inner.flush() + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + LineWriterShim::new(&mut self.inner).write_vectored(bufs) + } + + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all(buf) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all_vectored(bufs) + } + + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_fmt(fmt) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Write> fmt::Debug for LineWriter<W> +where + W: fmt::Debug, +{ + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("LineWriter") + .field("writer", &self.get_ref()) + .field( + "buffer", + &format_args!("{}/{}", self.inner.buffer().len(), self.inner.capacity()), + ) + .finish() + } +} diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs new file mode 100644 index 00000000000..a80d08db869 --- /dev/null +++ b/library/std/src/io/buffered/linewritershim.rs @@ -0,0 +1,270 @@ +use crate::io::{self, BufWriter, IoSlice, Write}; +use crate::memchr; + +/// Private helper struct for implementing the line-buffered writing logic. +/// This shim temporarily wraps a BufWriter, and uses its internals to +/// implement a line-buffered writer (specifically by using the internal +/// methods like write_to_buf and flush_buf). In this way, a more +/// efficient abstraction can be created than one that only had access to +/// `write` and `flush`, without needlessly duplicating a lot of the +/// implementation details of BufWriter. This also allows existing +/// `BufWriters` to be temporarily given line-buffering logic; this is what +/// enables Stdout to be alternately in line-buffered or block-buffered mode. +#[derive(Debug)] +pub struct LineWriterShim<'a, W: Write> { + buffer: &'a mut BufWriter<W>, +} + +impl<'a, W: Write> LineWriterShim<'a, W> { + pub fn new(buffer: &'a mut BufWriter<W>) -> Self { + Self { buffer } + } + + /// Get a mutable reference to the inner writer (that is, the writer + /// wrapped by the BufWriter). Be careful with this writer, as writes to + /// it will bypass the buffer. + fn inner_mut(&mut self) -> &mut W { + self.buffer.get_mut() + } + + /// Get the content currently buffered in self.buffer + fn buffered(&self) -> &[u8] { + self.buffer.buffer() + } + + /// Flush the buffer iff the last byte is a newline (indicating that an + /// earlier write only succeeded partially, and we want to retry flushing + /// the buffered line before continuing with a subsequent write) + fn flush_if_completed_line(&mut self) -> io::Result<()> { + match self.buffered().last().copied() { + Some(b'\n') => self.buffer.flush_buf(), + _ => Ok(()), + } + } +} + +impl<'a, W: Write> Write for LineWriterShim<'a, W> { + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. Returns the number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. If that write only reports a partial + /// success, the remaining data will be buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it ends with a + /// newline, even if the incoming data does not contain any newlines. + fn write(&mut self, buf: &[u8]) -> io::Result<usize> { + let newline_idx = match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + return self.buffer.write(buf); + } + // Otherwise, arrange for the lines to be written directly to the + // inner writer. + Some(newline_idx) => newline_idx + 1, + }; + + // Flush existing content to prepare for our write. We have to do this + // before attempting to write `buf` in order to maintain consistency; + // if we add `buf` to the buffer then try to flush it all at once, + // we're obligated to return Ok(), which would mean suppressing any + // errors that occur during flush. + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let lines = &buf[..newline_idx]; + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.buffer.panicked here. + let flushed = self.inner_mut().write(lines)?; + + // If buffer returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Now that the write has succeeded, buffer the rest (or as much of + // the rest as possible). If there were any unwritten newlines, we + // only buffer out to the last unwritten newline that fits in the + // buffer; this helps prevent flushing partial lines on subsequent + // calls to LineWriterShim::write. + + // Handle the cases in order of most-common to least-common, under + // the presumption that most writes succeed in totality, and that most + // writes are smaller than the buffer. + // - Is this a partial line (ie, no newlines left in the unwritten tail) + // - If not, does the data out to the last unwritten newline fit in + // the buffer? + // - If not, scan for the last newline that *does* fit in the buffer + let tail = if flushed >= newline_idx { + &buf[flushed..] + } else if newline_idx - flushed <= self.buffer.capacity() { + &buf[flushed..newline_idx] + } else { + let scan_area = &buf[flushed..]; + let scan_area = &scan_area[..self.buffer.capacity()]; + match memchr::memrchr(b'\n', scan_area) { + Some(newline_idx) => &scan_area[..newline_idx + 1], + None => scan_area, + } + }; + + let buffered = self.buffer.write_to_buf(tail); + Ok(flushed + buffered) + } + + fn flush(&mut self) -> io::Result<()> { + self.buffer.flush() + } + + /// Write some vectored data into this BufReader with line buffering. This + /// means that, if any newlines are present in the data, the data up to + /// and including the buffer containing the last newline is sent directly + /// to the inner writer, and the data after it is buffered. Returns the + /// number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines. + /// + /// Because sorting through an array of `IoSlice` can be a bit convoluted, + /// This method differs from write in the following ways: + /// + /// - It attempts to write the full content of all the buffers up to and + /// including the one containing the last newline. This means that it + /// may attempt to write a partial line, that buffer has data past the + /// newline. + /// - If the write only reports partial success, it does not attempt to + /// find the precise location of the written bytes and buffer the rest. + /// + /// If the underlying vector doesn't support vectored writing, we instead + /// simply write the first non-empty buffer with `write`. This way, we + /// get the benefits of more granular partial-line handling without losing + /// anything in efficiency + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { + // If there's no specialized behavior for write_vectored, just use + // write. This has the benefit of more granular partial-line handling. + if !self.is_write_vectored() { + return match bufs.iter().find(|buf| !buf.is_empty()) { + Some(buf) => self.write(buf), + None => Ok(0), + }; + } + + // Find the buffer containing the last newline + let last_newline_buf_idx = bufs + .iter() + .enumerate() + .rev() + .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); + + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write + let last_newline_buf_idx = match last_newline_buf_idx { + // No newlines; just do a normal buffered write + None => { + self.flush_if_completed_line()?; + return self.buffer.write_vectored(bufs); + } + Some(i) => i, + }; + + // Flush existing content to prepare for our write + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.panicked here. + let flushed = self.inner_mut().write_vectored(lines)?; + + // If inner returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Don't try to reconstruct the exact amount written; just bail + // in the event of a partial write + let lines_len = lines.iter().map(|buf| buf.len()).sum(); + if flushed < lines_len { + return Ok(flushed); + } + + // Now that the write has succeeded, buffer the rest (or as much of the + // rest as possible) + let buffered: usize = tail + .iter() + .filter(|buf| !buf.is_empty()) + .map(|buf| self.buffer.write_to_buf(buf)) + .take_while(|&n| n > 0) + .sum(); + + Ok(flushed + buffered) + } + + fn is_write_vectored(&self) -> bool { + self.buffer.is_write_vectored() + } + + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines, even if the incoming data does not contain any newlines. + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + self.buffer.write_all(buf) + } + Some(newline_idx) => { + let (lines, tail) = buf.split_at(newline_idx + 1); + + if self.buffered().is_empty() { + self.inner_mut().write_all(lines)?; + } else { + // If there is any buffered data, we add the incoming lines + // to that buffer before flushing, which saves us at least + // one write call. We can't really do this with `write`, + // since we can't do this *and* not suppress errors *and* + // report a consistent state to the caller in a return + // value, but here in write_all it's fine. + self.buffer.write_all(lines)?; + self.buffer.flush_buf()?; + } + + self.buffer.write_all(tail) + } + } + } +} diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs new file mode 100644 index 00000000000..f9caeaf98e2 --- /dev/null +++ b/library/std/src/io/buffered/mod.rs @@ -0,0 +1,151 @@ +//! Buffering wrappers for I/O traits + +mod bufreader; +mod bufwriter; +mod linewriter; +mod linewritershim; + +#[cfg(test)] +mod tests; + +use crate::error; +use crate::fmt; +use crate::io::Error; + +pub use bufreader::BufReader; +pub use bufwriter::BufWriter; +pub use linewriter::LineWriter; +use linewritershim::LineWriterShim; + +/// An error returned by [`BufWriter::into_inner`] which combines an error that +/// happened while writing out the buffer, and the buffered writer object +/// which may be used to recover from the condition. +/// +/// # Examples +/// +/// ```no_run +/// use std::io::BufWriter; +/// use std::net::TcpStream; +/// +/// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); +/// +/// // do stuff with the stream +/// +/// // we want to get our `TcpStream` back, so let's try: +/// +/// let stream = match stream.into_inner() { +/// Ok(s) => s, +/// Err(e) => { +/// // Here, e is an IntoInnerError +/// panic!("An error occurred"); +/// } +/// }; +/// ``` +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IntoInnerError<W>(W, Error); + +impl<W> IntoInnerError<W> { + /// Construct a new IntoInnerError + fn new(writer: W, error: Error) -> Self { + Self(writer, error) + } + + /// Helper to construct a new IntoInnerError; intended to help with + /// adapters that wrap other adapters + fn new_wrapped<W2>(self, f: impl FnOnce(W) -> W2) -> IntoInnerError<W2> { + let Self(writer, error) = self; + IntoInnerError::new(f(writer), error) + } + + /// Returns the error which caused the call to [`BufWriter::into_inner()`] + /// to fail. + /// + /// This error was returned when attempting to write the internal buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's log the inner error. + /// // + /// // We'll just 'log' to stdout for this example. + /// println!("{}", e.error()); + /// + /// panic!("An unexpected error occurred."); + /// } + /// }; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn error(&self) -> &Error { + &self.1 + } + + /// Returns the buffered writer instance which generated the error. + /// + /// The returned object can be used for error recovery, such as + /// re-inspecting the buffer. + /// + /// # Examples + /// + /// ```no_run + /// use std::io::BufWriter; + /// use std::net::TcpStream; + /// + /// let mut stream = BufWriter::new(TcpStream::connect("127.0.0.1:34254").unwrap()); + /// + /// // do stuff with the stream + /// + /// // we want to get our `TcpStream` back, so let's try: + /// + /// let stream = match stream.into_inner() { + /// Ok(s) => s, + /// Err(e) => { + /// // Here, e is an IntoInnerError, let's re-examine the buffer: + /// let buffer = e.into_inner(); + /// + /// // do stuff to try to recover + /// + /// // afterwards, let's just return the stream + /// buffer.into_inner().unwrap() + /// } + /// }; + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + pub fn into_inner(self) -> W { + self.0 + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W> From<IntoInnerError<W>> for Error { + fn from(iie: IntoInnerError<W>) -> Error { + iie.1 + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + error::Error::description(self.error()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<W> fmt::Display for IntoInnerError<W> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.error().fmt(f) + } +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index d4cc2cd239b..30e7a7f3c3b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -85,7 +85,7 @@ //! # Contributing changes to the documentation //! //! Check out the rust contribution guidelines [here]( -//! https://rustc-dev-guide.rust-lang.org/getting-started.html). +//! https://rustc-dev-guide.rust-lang.org/contributing.html#writing-documentation). //! The source for this documentation can be found on //! [GitHub](https://github.com/rust-lang/rust). //! To contribute changes, make sure you read the guidelines first, then submit @@ -319,7 +319,7 @@ #![feature(unsafe_block_in_unsafe_fn)] #![feature(unsafe_cell_get_mut)] #![feature(unsafe_cell_raw_get)] -#![feature(untagged_unions)] +#![cfg_attr(bootstrap, feature(untagged_unions))] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] #![feature(wake_trait)] diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs index ff23c3d67e3..9b7af97616c 100644 --- a/library/std/src/os/linux/fs.rs +++ b/library/std/src/os/linux/fs.rs @@ -20,7 +20,7 @@ pub trait MetadataExt { /// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the /// cross-Unix abstractions contained within the raw stat. /// - /// [`stat`]: crate::os::linux::raw::stat + /// [`stat`]: struct@crate::os::linux::raw::stat /// /// # Examples /// diff --git a/library/std/src/os/vxworks/fs.rs b/library/std/src/os/vxworks/fs.rs index 5a7e5bcaa76..77e6238ca1f 100644 --- a/library/std/src/os/vxworks/fs.rs +++ b/library/std/src/os/vxworks/fs.rs @@ -26,10 +26,16 @@ pub trait MetadataExt { #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_atime(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_atime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_mtime(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_mtime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_ctime(&self) -> i64; #[stable(feature = "metadata_ext2", since = "1.8.0")] + fn st_ctime_nsec(&self) -> i64; + #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blksize(&self) -> u64; #[stable(feature = "metadata_ext2", since = "1.8.0")] fn st_blocks(&self) -> u64; @@ -66,12 +72,21 @@ impl MetadataExt for Metadata { fn st_atime(&self) -> i64 { self.as_inner().as_inner().st_atime as i64 } + fn st_atime_nsec(&self) -> i64 { + 0 + } fn st_mtime(&self) -> i64 { self.as_inner().as_inner().st_mtime as i64 } + fn st_mtime_nsec(&self) -> i64 { + 0 + } fn st_ctime(&self) -> i64 { self.as_inner().as_inner().st_ctime as i64 } + fn st_ctime_nsec(&self) -> i64 { + 0 + } fn st_blksize(&self) -> u64 { self.as_inner().as_inner().st_blksize as u64 } diff --git a/library/std/src/os/vxworks/raw.rs b/library/std/src/os/vxworks/raw.rs index 29a0af5645e..cb41ddfe2a9 100644 --- a/library/std/src/os/vxworks/raw.rs +++ b/library/std/src/os/vxworks/raw.rs @@ -5,3 +5,6 @@ use crate::os::raw::c_ulong; #[stable(feature = "pthread_t", since = "1.8.0")] pub type pthread_t = c_ulong; + +#[stable(feature = "raw_ext", since = "1.1.0")] +pub use libc::{blkcnt_t, blksize_t, dev_t, ino_t, mode_t, nlink_t, off_t, time_t}; diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 6fa73042a30..50bd2a03b62 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1009,7 +1009,7 @@ impl FusedIterator for Ancestors<'_> {} /// [`set_extension`]: PathBuf::set_extension /// /// More details about the overall approach can be found in -/// the [module documentation](index.html). +/// the [module documentation](self). /// /// # Examples /// @@ -1655,7 +1655,7 @@ impl AsRef<OsStr> for PathBuf { /// see [`PathBuf`]. /// /// More details about the overall approach can be found in -/// the [module documentation](index.html). +/// the [module documentation](self). /// /// # Examples /// diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 81bbf376378..ae678479234 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1118,6 +1118,8 @@ mod prim_ref {} /// For more information and a list of supported ABIs, see [the nomicon's /// section on foreign calling conventions][nomicon-abi]. /// +/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions +/// /// ### Variadic functions /// /// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them diff --git a/library/std/src/sys/cloudabi/condvar.rs b/library/std/src/sys/cloudabi/condvar.rs index 82d89b260fa..f09bc01701b 100644 --- a/library/std/src/sys/cloudabi/condvar.rs +++ b/library/std/src/sys/cloudabi/condvar.rs @@ -1,4 +1,3 @@ -use crate::cell::UnsafeCell; use crate::mem; use crate::sync::atomic::{AtomicU32, Ordering}; use crate::sys::cloudabi::abi; @@ -12,7 +11,7 @@ extern "C" { } pub struct Condvar { - condvar: UnsafeCell<AtomicU32>, + condvar: AtomicU32, } pub type MovableCondvar = Condvar; @@ -20,29 +19,28 @@ pub type MovableCondvar = Condvar; unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} -const NEW: Condvar = - Condvar { condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)) }; - impl Condvar { pub const fn new() -> Condvar { - NEW + Condvar { condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0) } } pub unsafe fn init(&mut self) {} pub unsafe fn notify_one(&self) { - let condvar = self.condvar.get(); - if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { - let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1); + if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { + let ret = abi::condvar_signal( + &self.condvar as *const AtomicU32 as *mut abi::condvar, + abi::scope::PRIVATE, + 1, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to signal on condition variable"); } } pub unsafe fn notify_all(&self) { - let condvar = self.condvar.get(); - if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { + if self.condvar.load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 { let ret = abi::condvar_signal( - condvar as *mut abi::condvar, + &self.condvar as *const AtomicU32 as *mut abi::condvar, abi::scope::PRIVATE, abi::nthreads::MAX, ); @@ -53,20 +51,19 @@ impl Condvar { pub unsafe fn wait(&self, mutex: &Mutex) { let mutex = mutex::raw(mutex); assert_eq!( - (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This lock is not write-locked by this thread" ); // Call into the kernel to wait on the condition variable. - let condvar = self.condvar.get(); let subscription = abi::subscription { type_: abi::eventtype::CONDVAR, union: abi::subscription_union { condvar: abi::subscription_condvar { - condvar: condvar as *mut abi::condvar, + condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar, condvar_scope: abi::scope::PRIVATE, - lock: mutex as *mut abi::lock, + lock: mutex as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -86,13 +83,12 @@ impl Condvar { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { let mutex = mutex::raw(mutex); assert_eq!( - (*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + mutex.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This lock is not write-locked by this thread" ); // Call into the kernel to wait on the condition variable. - let condvar = self.condvar.get(); let timeout = checked_dur2intervals(&dur).expect("overflow converting duration to nanoseconds"); let subscriptions = [ @@ -100,9 +96,9 @@ impl Condvar { type_: abi::eventtype::CONDVAR, union: abi::subscription_union { condvar: abi::subscription_condvar { - condvar: condvar as *mut abi::condvar, + condvar: &self.condvar as *const AtomicU32 as *mut abi::condvar, condvar_scope: abi::scope::PRIVATE, - lock: mutex as *mut abi::lock, + lock: mutex as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -124,7 +120,7 @@ impl Condvar { let mut nevents: mem::MaybeUninit<usize> = mem::MaybeUninit::uninit(); let ret = abi::poll( subscriptions.as_ptr(), - mem::MaybeUninit::first_ptr_mut(&mut events), + mem::MaybeUninit::slice_as_mut_ptr(&mut events), 2, nevents.as_mut_ptr(), ); @@ -144,9 +140,8 @@ impl Condvar { } pub unsafe fn destroy(&self) { - let condvar = self.condvar.get(); assert_eq!( - (*condvar).load(Ordering::Relaxed), + self.condvar.load(Ordering::Relaxed), abi::CONDVAR_HAS_NO_WAITERS.0, "Attempted to destroy a condition variable with blocked threads" ); diff --git a/library/std/src/sys/cloudabi/mutex.rs b/library/std/src/sys/cloudabi/mutex.rs index 66839e05bf0..1203d8de0c5 100644 --- a/library/std/src/sys/cloudabi/mutex.rs +++ b/library/std/src/sys/cloudabi/mutex.rs @@ -1,4 +1,4 @@ -use crate::cell::UnsafeCell; +use crate::cell::Cell; use crate::mem; use crate::mem::MaybeUninit; use crate::sync::atomic::{AtomicU32, Ordering}; @@ -17,7 +17,7 @@ pub struct Mutex(RWLock); pub type MovableMutex = Mutex; -pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 { +pub unsafe fn raw(m: &Mutex) -> &AtomicU32 { rwlock::raw(&m.0) } @@ -50,28 +50,23 @@ impl Mutex { } pub struct ReentrantMutex { - lock: UnsafeCell<MaybeUninit<AtomicU32>>, - recursion: UnsafeCell<MaybeUninit<u32>>, + lock: AtomicU32, + recursion: Cell<u32>, } +unsafe impl Send for ReentrantMutex {} +unsafe impl Sync for ReentrantMutex {} + impl ReentrantMutex { pub const unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { - lock: UnsafeCell::new(MaybeUninit::uninit()), - recursion: UnsafeCell::new(MaybeUninit::uninit()), - } + ReentrantMutex { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0), recursion: Cell::new(0) } } - pub unsafe fn init(&self) { - *self.lock.get() = MaybeUninit::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)); - *self.recursion.get() = MaybeUninit::new(0); - } + pub unsafe fn init(&self) {} pub unsafe fn try_lock(&self) -> bool { // Attempt to acquire the lock. - let lock = (*self.lock.get()).as_mut_ptr(); - let recursion = (*self.recursion.get()).as_mut_ptr(); - if let Err(old) = (*lock).compare_exchange( + if let Err(old) = self.lock.compare_exchange( abi::LOCK_UNLOCKED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, Ordering::Acquire, @@ -80,14 +75,14 @@ impl ReentrantMutex { // If we fail to acquire the lock, it may be the case // that we've already acquired it and may need to recurse. if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 { - *recursion += 1; + self.recursion.set(self.recursion.get() + 1); true } else { false } } else { // Success. - assert_eq!(*recursion, 0, "Mutex has invalid recursion count"); + assert_eq!(self.recursion.get(), 0, "Mutex has invalid recursion count"); true } } @@ -95,7 +90,7 @@ impl ReentrantMutex { pub unsafe fn lock(&self) { if !self.try_lock() { // Call into the kernel to acquire a write lock. - let lock = self.lock.get(); + let lock = &self.lock as *const AtomicU32; let subscription = abi::subscription { type_: abi::eventtype::LOCK_WRLOCK, union: abi::subscription_union { @@ -116,17 +111,17 @@ impl ReentrantMutex { } pub unsafe fn unlock(&self) { - let lock = (*self.lock.get()).as_mut_ptr(); - let recursion = (*self.recursion.get()).as_mut_ptr(); assert_eq!( - (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This mutex is locked by a different thread" ); - if *recursion > 0 { - *recursion -= 1; - } else if !(*lock) + let r = self.recursion.get(); + if r > 0 { + self.recursion.set(r - 1); + } else if !self + .lock .compare_exchange( __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, abi::LOCK_UNLOCKED.0, @@ -137,19 +132,20 @@ impl ReentrantMutex { { // Lock is managed by kernelspace. Call into the kernel // to unblock waiting threads. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); + let ret = abi::lock_unlock( + &self.lock as *const AtomicU32 as *mut abi::lock, + abi::scope::PRIVATE, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex"); } } pub unsafe fn destroy(&self) { - let lock = (*self.lock.get()).as_mut_ptr(); - let recursion = (*self.recursion.get()).as_mut_ptr(); assert_eq!( - (*lock).load(Ordering::Relaxed), + self.lock.load(Ordering::Relaxed), abi::LOCK_UNLOCKED.0, "Attempted to destroy locked mutex" ); - assert_eq!(*recursion, 0, "Recursion counter invalid"); + assert_eq!(self.recursion.get(), 0, "Recursion counter invalid"); } } diff --git a/library/std/src/sys/cloudabi/rwlock.rs b/library/std/src/sys/cloudabi/rwlock.rs index b8af5af1d70..508de8ba47c 100644 --- a/library/std/src/sys/cloudabi/rwlock.rs +++ b/library/std/src/sys/cloudabi/rwlock.rs @@ -1,4 +1,3 @@ -use crate::cell::UnsafeCell; use crate::mem; use crate::mem::MaybeUninit; use crate::sync::atomic::{AtomicU32, Ordering}; @@ -13,28 +12,25 @@ extern "C" { static mut RDLOCKS_ACQUIRED: u32 = 0; pub struct RWLock { - lock: UnsafeCell<AtomicU32>, + lock: AtomicU32, } -pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 { - r.lock.get() +pub unsafe fn raw(r: &RWLock) -> &AtomicU32 { + &r.lock } unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} -const NEW: RWLock = RWLock { lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)) }; - impl RWLock { pub const fn new() -> RWLock { - NEW + RWLock { lock: AtomicU32::new(abi::LOCK_UNLOCKED.0) } } pub unsafe fn try_read(&self) -> bool { - let lock = self.lock.get(); let mut old = abi::LOCK_UNLOCKED.0; while let Err(cur) = - (*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed) + self.lock.compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed) { if (cur & abi::LOCK_WRLOCKED.0) != 0 { // Another thread already has a write lock. @@ -61,12 +57,11 @@ impl RWLock { pub unsafe fn read(&self) { if !self.try_read() { // Call into the kernel to acquire a read lock. - let lock = self.lock.get(); let subscription = abi::subscription { type_: abi::eventtype::LOCK_RDLOCK, union: abi::subscription_union { lock: abi::subscription_lock { - lock: lock as *mut abi::lock, + lock: &self.lock as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -96,11 +91,10 @@ impl RWLock { assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count"); let mut old = 1; loop { - let lock = self.lock.get(); if old == 1 | abi::LOCK_KERNEL_MANAGED.0 { // Last read lock while threads are waiting. Attempt to upgrade // to a write lock before calling into the kernel to unlock. - if let Err(cur) = (*lock).compare_exchange_weak( + if let Err(cur) = self.lock.compare_exchange_weak( old, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0, Ordering::Acquire, @@ -109,7 +103,10 @@ impl RWLock { old = cur; } else { // Call into the kernel to unlock. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); + let ret = abi::lock_unlock( + &self.lock as *const AtomicU32 as *mut abi::lock, + abi::scope::PRIVATE, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); break; } @@ -122,7 +119,7 @@ impl RWLock { 0, "Attempted to read-unlock a write-locked rwlock" ); - if let Err(cur) = (*lock).compare_exchange_weak( + if let Err(cur) = self.lock.compare_exchange_weak( old, old - 1, Ordering::Acquire, @@ -140,8 +137,7 @@ impl RWLock { pub unsafe fn try_write(&self) -> bool { // Attempt to acquire the lock. - let lock = self.lock.get(); - if let Err(old) = (*lock).compare_exchange( + if let Err(old) = self.lock.compare_exchange( abi::LOCK_UNLOCKED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, Ordering::Acquire, @@ -163,12 +159,11 @@ impl RWLock { pub unsafe fn write(&self) { if !self.try_write() { // Call into the kernel to acquire a write lock. - let lock = self.lock.get(); let subscription = abi::subscription { type_: abi::eventtype::LOCK_WRLOCK, union: abi::subscription_union { lock: abi::subscription_lock { - lock: lock as *mut abi::lock, + lock: &self.lock as *const AtomicU32 as *mut abi::lock, lock_scope: abi::scope::PRIVATE, }, }, @@ -184,14 +179,14 @@ impl RWLock { } pub unsafe fn write_unlock(&self) { - let lock = self.lock.get(); assert_eq!( - (*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, + self.lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, "This rwlock is not write-locked by this thread" ); - if !(*lock) + if !self + .lock .compare_exchange( __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, abi::LOCK_UNLOCKED.0, @@ -202,15 +197,17 @@ impl RWLock { { // Lock is managed by kernelspace. Call into the kernel // to unblock waiting threads. - let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE); + let ret = abi::lock_unlock( + &self.lock as *const AtomicU32 as *mut abi::lock, + abi::scope::PRIVATE, + ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock"); } } pub unsafe fn destroy(&self) { - let lock = self.lock.get(); assert_eq!( - (*lock).load(Ordering::Relaxed), + self.lock.load(Ordering::Relaxed), abi::LOCK_UNLOCKED.0, "Attempted to destroy locked rwlock" ); diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index f7c3f163718..69676472493 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -70,7 +70,8 @@ impl DoubleEndedIterator for Args { target_os = "haiku", target_os = "l4re", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] mod imp { use super::Args; diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index 4b9f4ceb29c..66bbc1c5854 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -650,6 +650,9 @@ pub trait MetadataExt { /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn blocks(&self) -> u64; + #[cfg(target_os = "vxworks")] + #[stable(feature = "metadata_ext", since = "1.1.0")] + fn attrib(&self) -> u8; } #[stable(feature = "metadata_ext", since = "1.1.0")] @@ -702,6 +705,10 @@ impl MetadataExt for fs::Metadata { fn blocks(&self) -> u64 { self.st_blocks() } + #[cfg(target_os = "vxworks")] + fn attrib(&self) -> u8 { + self.st_attrib() + } } /// Unix-specific extensions for [`fs::FileType`]. diff --git a/library/std/src/sys/unix/ext/process.rs b/library/std/src/sys/unix/ext/process.rs index 82527c40e91..3615a8a5ee8 100644 --- a/library/std/src/sys/unix/ext/process.rs +++ b/library/std/src/sys/unix/ext/process.rs @@ -16,12 +16,20 @@ pub trait CommandExt { /// `setuid` call in the child process. Failure in the `setuid` /// call will cause the spawn to fail. #[stable(feature = "rust1", since = "1.0.0")] - fn uid(&mut self, id: u32) -> &mut process::Command; + fn uid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command; /// Similar to `uid`, but sets the group ID of the child process. This has /// the same semantics as the `uid` field. #[stable(feature = "rust1", since = "1.0.0")] - fn gid(&mut self, id: u32) -> &mut process::Command; + fn gid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command; /// Schedules a closure to be run just before the `exec` function is /// invoked. @@ -115,12 +123,20 @@ pub trait CommandExt { #[stable(feature = "rust1", since = "1.0.0")] impl CommandExt for process::Command { - fn uid(&mut self, id: u32) -> &mut process::Command { + fn uid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command { self.as_inner_mut().uid(id); self } - fn gid(&mut self, id: u32) -> &mut process::Command { + fn gid( + &mut self, + #[cfg(not(target_os = "vxworks"))] id: u32, + #[cfg(target_os = "vxworks")] id: u16, + ) -> &mut process::Command { self.as_inner_mut().gid(id); self } diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 2224a055d6d..d3a279a2355 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -200,7 +200,8 @@ impl FileDesc { target_os = "l4re", target_os = "linux", target_os = "haiku", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" )))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -217,7 +218,8 @@ impl FileDesc { target_os = "l4re", target_os = "linux", target_os = "haiku", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 8184c25afcf..d27d6e2c565 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -297,6 +297,7 @@ impl FileAttr { #[cfg(not(target_os = "netbsd"))] impl FileAttr { + #[cfg(not(target_os = "vxworks"))] pub fn modified(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_mtime as libc::time_t, @@ -304,6 +305,15 @@ impl FileAttr { })) } + #[cfg(target_os = "vxworks")] + pub fn modified(&self) -> io::Result<SystemTime> { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.st_mtime as libc::time_t, + tv_nsec: 0, + })) + } + + #[cfg(not(target_os = "vxworks"))] pub fn accessed(&self) -> io::Result<SystemTime> { Ok(SystemTime::from(libc::timespec { tv_sec: self.stat.st_atime as libc::time_t, @@ -311,6 +321,14 @@ impl FileAttr { })) } + #[cfg(target_os = "vxworks")] + pub fn accessed(&self) -> io::Result<SystemTime> { + Ok(SystemTime::from(libc::timespec { + tv_sec: self.stat.st_atime as libc::time_t, + tv_nsec: 0, + })) + } + #[cfg(any( target_os = "freebsd", target_os = "openbsd", @@ -535,12 +553,22 @@ impl DirEntry { lstat(&self.path()) } - #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "haiku"))] + #[cfg(any( + target_os = "solaris", + target_os = "illumos", + target_os = "haiku", + target_os = "vxworks" + ))] pub fn file_type(&self) -> io::Result<FileType> { lstat(&self.path()).map(|m| m.file_type()) } - #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "haiku")))] + #[cfg(not(any( + target_os = "solaris", + target_os = "illumos", + target_os = "haiku", + target_os = "vxworks" + )))] pub fn file_type(&self) -> io::Result<FileType> { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -565,7 +593,8 @@ impl DirEntry { target_os = "haiku", target_os = "l4re", target_os = "fuchsia", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 @@ -603,7 +632,8 @@ impl DirEntry { target_os = "linux", target_os = "emscripten", target_os = "l4re", - target_os = "haiku" + target_os = "haiku", + target_os = "vxworks" ))] fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() } @@ -757,11 +787,25 @@ impl File { unsafe fn os_datasync(fd: c_int) -> c_int { libc::fcntl(fd, libc::F_FULLFSYNC) } - #[cfg(target_os = "linux")] + #[cfg(any( + target_os = "freebsd", + target_os = "linux", + target_os = "android", + target_os = "netbsd", + target_os = "openbsd" + ))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) } - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))] + #[cfg(not(any( + target_os = "android", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd" + )))] unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) } @@ -901,13 +945,25 @@ impl fmt::Debug for File { Some(PathBuf::from(OsString::from_vec(buf))) } - #[cfg(not(any(target_os = "linux", target_os = "macos")))] + #[cfg(target_os = "vxworks")] + fn get_path(fd: c_int) -> Option<PathBuf> { + let mut buf = vec![0; libc::PATH_MAX as usize]; + let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; + if n == -1 { + return None; + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "vxworks")))] fn get_path(_fd: c_int) -> Option<PathBuf> { // FIXME(#24570): implement this for other Unix platforms None } - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any(target_os = "linux", target_os = "macos", target_os = "vxworks"))] fn get_mode(fd: c_int) -> Option<(bool, bool)> { let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; if mode == -1 { @@ -921,7 +977,7 @@ impl fmt::Debug for File { } } - #[cfg(not(any(target_os = "linux", target_os = "macos")))] + #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "vxworks")))] fn get_mode(_fd: c_int) -> Option<(bool, bool)> { // FIXME(#24570): implement this for other Unix platforms None diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index 011325fddc5..74c7db27226 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -77,6 +77,7 @@ impl Socket { } } + #[cfg(not(target_os = "vxworks"))] pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> { unsafe { let mut fds = [0, 0]; @@ -98,6 +99,11 @@ impl Socket { } } + #[cfg(target_os = "vxworks")] + pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> { + unimplemented!() + } + pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { self.set_nonblocking(true)?; let r = unsafe { @@ -366,7 +372,7 @@ impl IntoInner<c_int> for Socket { // res_init unconditionally, we call it only when we detect we're linking // against glibc version < 2.26. (That is, when we both know its needed and // believe it's thread-safe). -#[cfg(target_env = "gnu")] +#[cfg(all(target_env = "gnu", not(target_os = "vxworks")))] fn on_resolver_failure() { use crate::sys; @@ -378,5 +384,5 @@ fn on_resolver_failure() { } } -#[cfg(not(target_env = "gnu"))] +#[cfg(any(not(target_env = "gnu"), target_os = "vxworks"))] fn on_resolver_failure() {} diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index c9f9ed01e12..d5e14bec765 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -37,7 +37,7 @@ cfg_if::cfg_if! { } extern "C" { - #[cfg(not(target_os = "dragonfly"))] + #[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] #[cfg_attr( any( target_os = "linux", @@ -67,18 +67,28 @@ extern "C" { } /// Returns the platform-specific value of errno -#[cfg(not(target_os = "dragonfly"))] +#[cfg(not(any(target_os = "dragonfly", target_os = "vxworks")))] pub fn errno() -> i32 { unsafe { (*errno_location()) as i32 } } /// Sets the platform-specific value of errno -#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly")))] // needed for readdir and syscall! +#[cfg(all(not(target_os = "linux"), not(target_os = "dragonfly"), not(target_os = "vxworks")))] // needed for readdir and syscall! #[allow(dead_code)] // but not all target cfgs actually end up using it pub fn set_errno(e: i32) { unsafe { *errno_location() = e as c_int } } +#[cfg(target_os = "vxworks")] +pub fn errno() -> i32 { + unsafe { libc::errnoGet() } +} + +#[cfg(target_os = "vxworks")] +pub fn set_errno(e: i32) { + unsafe { libc::errnoSet(e as c_int) }; +} + #[cfg(target_os = "dragonfly")] pub fn errno() -> i32 { extern "C" { @@ -439,6 +449,19 @@ pub fn current_exe() -> io::Result<PathBuf> { Err(io::Error::new(ErrorKind::Other, "Not yet implemented!")) } +#[cfg(target_os = "vxworks")] +pub fn current_exe() -> io::Result<PathBuf> { + #[cfg(test)] + use realstd::env; + + #[cfg(not(test))] + use crate::env; + + let exe_path = env::args().next().unwrap(); + let path = path::Path::new(&exe_path); + path.canonicalize() +} + pub struct Env { iter: vec::IntoIter<(OsString, OsString)>, _dont_send_or_sync_me: PhantomData<*mut ()>, @@ -470,7 +493,7 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> StaticMutexGuard<'static> { +pub unsafe fn env_lock() -> StaticMutexGuard { // It is UB to attempt to acquire this mutex reentrantly! static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() @@ -568,7 +591,8 @@ pub fn home_dir() -> Option<PathBuf> { target_os = "android", target_os = "ios", target_os = "emscripten", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] unsafe fn fallback() -> Option<OsString> { None @@ -577,7 +601,8 @@ pub fn home_dir() -> Option<PathBuf> { target_os = "android", target_os = "ios", target_os = "emscripten", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" )))] unsafe fn fallback() -> Option<OsString> { let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 9ddd4ad4000..4b29b7020eb 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -24,6 +24,8 @@ cfg_if::cfg_if! { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { const DEV_NULL: &str = "null:\0"; + } else if #[cfg(target_os = "vxworks")] { + const DEV_NULL: &str = "/null\0"; } else { const DEV_NULL: &str = "/dev/null\0"; } @@ -48,7 +50,7 @@ cfg_if::cfg_if! { raw[bit / 8] |= 1 << (bit % 8); return 0; } - } else { + } else if #[cfg(not(target_os = "vxworks"))] { pub use libc::{sigemptyset, sigaddset}; } } diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index eb600d2465c..b5be92e3eae 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -6,6 +6,10 @@ use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; +#[cfg(target_os = "vxworks")] +use libc::RTP_ID as pid_t; + +#[cfg(not(target_os = "vxworks"))] use libc::{c_int, gid_t, pid_t, uid_t}; //////////////////////////////////////////////////////////////////////////////// @@ -319,9 +323,9 @@ impl Command { let mut p = Process { pid: 0, status: None }; - struct PosixSpawnFileActions(MaybeUninit<libc::posix_spawn_file_actions_t>); + struct PosixSpawnFileActions<'a>(&'a mut MaybeUninit<libc::posix_spawn_file_actions_t>); - impl Drop for PosixSpawnFileActions { + impl Drop for PosixSpawnFileActions<'_> { fn drop(&mut self) { unsafe { libc::posix_spawn_file_actions_destroy(self.0.as_mut_ptr()); @@ -329,9 +333,9 @@ impl Command { } } - struct PosixSpawnattr(MaybeUninit<libc::posix_spawnattr_t>); + struct PosixSpawnattr<'a>(&'a mut MaybeUninit<libc::posix_spawnattr_t>); - impl Drop for PosixSpawnattr { + impl Drop for PosixSpawnattr<'_> { fn drop(&mut self) { unsafe { libc::posix_spawnattr_destroy(self.0.as_mut_ptr()); @@ -339,59 +343,65 @@ impl Command { } } + fn cvt_nz(error: libc::c_int) -> io::Result<()> { + if error == 0 { Ok(()) } else { Err(io::Error::from_raw_os_error(error)) } + } + unsafe { - let mut file_actions = PosixSpawnFileActions(MaybeUninit::uninit()); - let mut attrs = PosixSpawnattr(MaybeUninit::uninit()); + let mut attrs = MaybeUninit::uninit(); + cvt_nz(libc::posix_spawnattr_init(attrs.as_mut_ptr()))?; + let attrs = PosixSpawnattr(&mut attrs); - libc::posix_spawnattr_init(attrs.0.as_mut_ptr()); - libc::posix_spawn_file_actions_init(file_actions.0.as_mut_ptr()); + let mut file_actions = MaybeUninit::uninit(); + cvt_nz(libc::posix_spawn_file_actions_init(file_actions.as_mut_ptr()))?; + let file_actions = PosixSpawnFileActions(&mut file_actions); if let Some(fd) = stdio.stdin.fd() { - cvt(libc::posix_spawn_file_actions_adddup2( + cvt_nz(libc::posix_spawn_file_actions_adddup2( file_actions.0.as_mut_ptr(), fd, libc::STDIN_FILENO, ))?; } if let Some(fd) = stdio.stdout.fd() { - cvt(libc::posix_spawn_file_actions_adddup2( + cvt_nz(libc::posix_spawn_file_actions_adddup2( file_actions.0.as_mut_ptr(), fd, libc::STDOUT_FILENO, ))?; } if let Some(fd) = stdio.stderr.fd() { - cvt(libc::posix_spawn_file_actions_adddup2( + cvt_nz(libc::posix_spawn_file_actions_adddup2( file_actions.0.as_mut_ptr(), fd, libc::STDERR_FILENO, ))?; } if let Some((f, cwd)) = addchdir { - cvt(f(file_actions.0.as_mut_ptr(), cwd.as_ptr()))?; + cvt_nz(f(file_actions.0.as_mut_ptr(), cwd.as_ptr()))?; } let mut set = MaybeUninit::<libc::sigset_t>::uninit(); cvt(sigemptyset(set.as_mut_ptr()))?; - cvt(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), set.as_ptr()))?; + cvt_nz(libc::posix_spawnattr_setsigmask(attrs.0.as_mut_ptr(), set.as_ptr()))?; cvt(sigaddset(set.as_mut_ptr(), libc::SIGPIPE))?; - cvt(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), set.as_ptr()))?; + cvt_nz(libc::posix_spawnattr_setsigdefault(attrs.0.as_mut_ptr(), set.as_ptr()))?; let flags = libc::POSIX_SPAWN_SETSIGDEF | libc::POSIX_SPAWN_SETSIGMASK; - cvt(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?; + cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?; // Make sure we synchronize access to the global `environ` resource let _env_lock = sys::os::env_lock(); let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); - let ret = libc::posix_spawnp( + cvt_nz(libc::posix_spawnp( &mut p.pid, self.get_program_cstr().as_ptr(), file_actions.0.as_ptr(), attrs.0.as_ptr(), self.get_argv().as_ptr() as *const _, envp as *const _, - ); - if ret == 0 { Ok(Some(p)) } else { Err(io::Error::from_raw_os_error(ret)) } + ))?; + Ok(Some(p)) } } } diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs index c74fc2b5903..d8474205352 100644 --- a/library/std/src/sys/unix/stack_overflow.rs +++ b/library/std/src/sys/unix/stack_overflow.rs @@ -219,7 +219,7 @@ mod imp { target_os = "solaris", target_os = "illumos", all(target_os = "netbsd", not(target_vendor = "rumprun")), - target_os = "openbsd" + target_os = "openbsd", )))] mod imp { pub unsafe fn init() {} diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 652219e28f6..fdf114d6df6 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -6,10 +6,12 @@ use crate::ptr; use crate::sys::{os, stack_overflow}; use crate::time::Duration; -#[cfg(not(target_os = "l4re"))] +#[cfg(not(any(target_os = "l4re", target_os = "vxworks")))] pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; #[cfg(target_os = "l4re")] pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; +#[cfg(target_os = "vxworks")] +pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024; pub struct Thread { id: libc::pthread_t, @@ -152,10 +154,11 @@ impl Thread { target_os = "haiku", target_os = "l4re", target_os = "emscripten", - target_os = "redox" + target_os = "redox", + target_os = "vxworks" ))] pub fn set_name(_name: &CStr) { - // Newlib, Haiku, and Emscripten have no way to set a thread name. + // Newlib, Haiku, Emscripten, and VxWorks have no way to set a thread name. } #[cfg(target_os = "fuchsia")] pub fn set_name(_name: &CStr) { diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs index f2a9cb5a0e8..fac4b05ad0b 100644 --- a/library/std/src/sys/unix/time.rs +++ b/library/std/src/sys/unix/time.rs @@ -117,8 +117,7 @@ impl Hash for Timespec { #[cfg(any(target_os = "macos", target_os = "ios"))] mod inner { use crate::fmt; - use crate::mem; - use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; + use crate::sync::atomic::{AtomicU64, Ordering}; use crate::sys::cvt; use crate::sys_common::mul_div_u64; use crate::time::Duration; @@ -233,31 +232,42 @@ mod inner { } fn info() -> mach_timebase_info { - static mut INFO: mach_timebase_info = mach_timebase_info { numer: 0, denom: 0 }; - static STATE: AtomicUsize = AtomicUsize::new(0); - - unsafe { - // If a previous thread has filled in this global state, use that. - if STATE.load(SeqCst) == 2 { - return INFO; - } + // INFO_BITS conceptually is an `Option<mach_timebase_info>`. We can do + // this in 64 bits because we know 0 is never a valid value for the + // `denom` field. + // + // Encoding this as a single `AtomicU64` allows us to use `Relaxed` + // operations, as we are only interested in in the effects on a single + // memory location. + static INFO_BITS: AtomicU64 = AtomicU64::new(0); + + // If a previous thread has initialized `INFO_BITS`, use it. + let info_bits = INFO_BITS.load(Ordering::Relaxed); + if info_bits != 0 { + return info_from_bits(info_bits); + } - // ... otherwise learn for ourselves ... - let mut info = mem::zeroed(); - extern "C" { - fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t; - } + // ... otherwise learn for ourselves ... + extern "C" { + fn mach_timebase_info(info: mach_timebase_info_t) -> kern_return_t; + } + let mut info = info_from_bits(0); + unsafe { mach_timebase_info(&mut info); - - // ... and attempt to be the one thread that stores it globally for - // all other threads - if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() { - INFO = info; - STATE.store(2, SeqCst); - } - return info; } + INFO_BITS.store(info_to_bits(info), Ordering::Relaxed); + info + } + + #[inline] + fn info_to_bits(info: mach_timebase_info) -> u64 { + ((info.denom as u64) << 32) | (info.numer as u64) + } + + #[inline] + fn info_from_bits(bits: u64) -> mach_timebase_info { + mach_timebase_info { numer: bits as u32, denom: (bits >> 32) as u32 } } } diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs index 80311d26819..2cdd9c4d19e 100644 --- a/library/std/src/sys/unsupported/common.rs +++ b/library/std/src/sys/unsupported/common.rs @@ -39,10 +39,13 @@ pub fn hashmap_random_keys() -> (u64, u64) { pub enum Void {} pub unsafe fn strlen(mut s: *const c_char) -> usize { - let mut n = 0; - while *s != 0 { - n += 1; - s = s.offset(1); + // SAFETY: The caller must guarantee `s` points to a valid 0-terminated string. + unsafe { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.offset(1); + } + n } - return n; } diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs index 8ba870c5dbc..d9efdec33d9 100644 --- a/library/std/src/sys/unsupported/mod.rs +++ b/library/std/src/sys/unsupported/mod.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + pub mod alloc; pub mod args; pub mod cmath; diff --git a/library/std/src/sys/unsupported/mutex.rs b/library/std/src/sys/unsupported/mutex.rs index 06ea9a1e2c1..b3203c16c50 100644 --- a/library/std/src/sys/unsupported/mutex.rs +++ b/library/std/src/sys/unsupported/mutex.rs @@ -1,7 +1,8 @@ -use crate::cell::UnsafeCell; +use crate::cell::Cell; pub struct Mutex { - locked: UnsafeCell<bool>, + // This platform has no threads, so we can use a Cell here. + locked: Cell<bool>, } pub type MovableMutex = Mutex; @@ -10,9 +11,8 @@ unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} // no threads on this platform impl Mutex { - #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")] pub const fn new() -> Mutex { - Mutex { locked: UnsafeCell::new(false) } + Mutex { locked: Cell::new(false) } } #[inline] @@ -20,25 +20,17 @@ impl Mutex { #[inline] pub unsafe fn lock(&self) { - let locked = self.locked.get(); - assert!(!*locked, "cannot recursively acquire mutex"); - *locked = true; + assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex"); } #[inline] pub unsafe fn unlock(&self) { - *self.locked.get() = false; + self.locked.set(false); } #[inline] pub unsafe fn try_lock(&self) -> bool { - let locked = self.locked.get(); - if *locked { - false - } else { - *locked = true; - true - } + self.locked.replace(true) == false } #[inline] diff --git a/library/std/src/sys/unsupported/rwlock.rs b/library/std/src/sys/unsupported/rwlock.rs index d37f34ac935..6982b2b155f 100644 --- a/library/std/src/sys/unsupported/rwlock.rs +++ b/library/std/src/sys/unsupported/rwlock.rs @@ -1,7 +1,8 @@ -use crate::cell::UnsafeCell; +use crate::cell::Cell; pub struct RWLock { - mode: UnsafeCell<isize>, + // This platform has no threads, so we can use a Cell here. + mode: Cell<isize>, } unsafe impl Send for RWLock {} @@ -9,14 +10,14 @@ unsafe impl Sync for RWLock {} // no threads on this platform impl RWLock { pub const fn new() -> RWLock { - RWLock { mode: UnsafeCell::new(0) } + RWLock { mode: Cell::new(0) } } #[inline] pub unsafe fn read(&self) { - let mode = self.mode.get(); - if *mode >= 0 { - *mode += 1; + let m = self.mode.get(); + if m >= 0 { + self.mode.set(m + 1); } else { rtabort!("rwlock locked for writing"); } @@ -24,9 +25,9 @@ impl RWLock { #[inline] pub unsafe fn try_read(&self) -> bool { - let mode = self.mode.get(); - if *mode >= 0 { - *mode += 1; + let m = self.mode.get(); + if m >= 0 { + self.mode.set(m + 1); true } else { false @@ -35,19 +36,15 @@ impl RWLock { #[inline] pub unsafe fn write(&self) { - let mode = self.mode.get(); - if *mode == 0 { - *mode = -1; - } else { + if self.mode.replace(-1) != 0 { rtabort!("rwlock locked for reading") } } #[inline] pub unsafe fn try_write(&self) -> bool { - let mode = self.mode.get(); - if *mode == 0 { - *mode = -1; + if self.mode.get() == 0 { + self.mode.set(-1); true } else { false @@ -56,12 +53,12 @@ impl RWLock { #[inline] pub unsafe fn read_unlock(&self) { - *self.mode.get() -= 1; + self.mode.set(self.mode.get() - 1); } #[inline] pub unsafe fn write_unlock(&self) { - *self.mode.get() += 1; + assert_eq!(self.mode.replace(0), -1); } #[inline] diff --git a/library/std/src/sys/vxworks/alloc.rs b/library/std/src/sys/vxworks/alloc.rs deleted file mode 100644 index 97a191d7232..00000000000 --- a/library/std/src/sys/vxworks/alloc.rs +++ /dev/null @@ -1,49 +0,0 @@ -use crate::alloc::{GlobalAlloc, Layout, System}; -use crate::ptr; -use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN}; - -#[stable(feature = "alloc_system_type", since = "1.28.0")] -unsafe impl GlobalAlloc for System { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut u8 - } else { - aligned_malloc(&layout) - } - } - - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut u8 - } else { - let ptr = self.alloc(layout.clone()); - if !ptr.is_null() { - ptr::write_bytes(ptr, 0, layout.size()); - } - ptr - } - } - - #[inline] - unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { - libc::free(ptr as *mut libc::c_void) - } - - #[inline] - unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { - if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 - } else { - realloc_fallback(self, ptr, layout, new_size) - } - } -} - -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - let mut out = ptr::null_mut(); - let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); - if ret != 0 { ptr::null_mut() } else { out as *mut u8 } -} diff --git a/library/std/src/sys/vxworks/args.rs b/library/std/src/sys/vxworks/args.rs deleted file mode 100644 index 30cf7a707c7..00000000000 --- a/library/std/src/sys/vxworks/args.rs +++ /dev/null @@ -1,95 +0,0 @@ -#![allow(dead_code)] // runtime init functions not used during testing -use crate::ffi::OsString; -use crate::marker::PhantomData; -use crate::vec; - -/// One-time global initialization. -pub unsafe fn init(argc: isize, argv: *const *const u8) { - imp::init(argc, argv) -} - -/// One-time global cleanup. -pub unsafe fn cleanup() { - imp::cleanup() -} - -/// Returns the command line arguments -pub fn args() -> Args { - imp::args() -} - -pub struct Args { - iter: vec::IntoIter<OsString>, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Args { - pub fn inner_debug(&self) -> &[OsString] { - self.iter.as_slice() - } -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option<OsString> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { - self.iter.len() - } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option<OsString> { - self.iter.next_back() - } -} - -mod imp { - use super::Args; - use crate::ffi::{CStr, OsString}; - use crate::marker::PhantomData; - use crate::ptr; - - use crate::sys_common::mutex::StaticMutex; - - static mut ARGC: isize = 0; - static mut ARGV: *const *const u8 = ptr::null(); - static LOCK: StaticMutex = StaticMutex::new(); - - pub unsafe fn init(argc: isize, argv: *const *const u8) { - let _guard = LOCK.lock(); - ARGC = argc; - ARGV = argv; - } - - pub unsafe fn cleanup() { - let _guard = LOCK.lock(); - ARGC = 0; - ARGV = ptr::null(); - } - - pub fn args() -> Args { - Args { iter: clone().into_iter(), _dont_send_or_sync_me: PhantomData } - } - - fn clone() -> Vec<OsString> { - unsafe { - let _guard = LOCK.lock(); - let ret = (0..ARGC) - .map(|i| { - let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char); - use crate::sys::vxworks::ext::ffi::OsStringExt; - OsStringExt::from_vec(cstr.to_bytes().to_vec()) - }) - .collect(); - return ret; - } - } -} diff --git a/library/std/src/sys/vxworks/cmath.rs b/library/std/src/sys/vxworks/cmath.rs deleted file mode 100644 index f327b69fc75..00000000000 --- a/library/std/src/sys/vxworks/cmath.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![cfg(not(test))] - -use libc::{c_double, c_float}; - -extern "C" { - pub fn acos(n: c_double) -> c_double; - pub fn acosf(n: c_float) -> c_float; - pub fn asin(n: c_double) -> c_double; - pub fn asinf(n: c_float) -> c_float; - pub fn atan(n: c_double) -> c_double; - pub fn atan2(a: c_double, b: c_double) -> c_double; - pub fn atan2f(a: c_float, b: c_float) -> c_float; - pub fn atanf(n: c_float) -> c_float; - pub fn cbrt(n: c_double) -> c_double; - pub fn cbrtf(n: c_float) -> c_float; - pub fn cosh(n: c_double) -> c_double; - pub fn coshf(n: c_float) -> c_float; - pub fn expm1(n: c_double) -> c_double; - pub fn expm1f(n: c_float) -> c_float; - pub fn fdim(a: c_double, b: c_double) -> c_double; - pub fn fdimf(a: c_float, b: c_float) -> c_float; - pub fn hypot(x: c_double, y: c_double) -> c_double; - pub fn hypotf(x: c_float, y: c_float) -> c_float; - pub fn log1p(n: c_double) -> c_double; - pub fn log1pf(n: c_float) -> c_float; - pub fn sinh(n: c_double) -> c_double; - pub fn sinhf(n: c_float) -> c_float; - pub fn tan(n: c_double) -> c_double; - pub fn tanf(n: c_float) -> c_float; - pub fn tanh(n: c_double) -> c_double; - pub fn tanhf(n: c_float) -> c_float; -} diff --git a/library/std/src/sys/vxworks/condvar.rs b/library/std/src/sys/vxworks/condvar.rs deleted file mode 100644 index b4724be7c7c..00000000000 --- a/library/std/src/sys/vxworks/condvar.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sys::mutex::{self, Mutex}; -use crate::time::Duration; - -pub struct Condvar { - inner: UnsafeCell<libc::pthread_cond_t>, -} - -pub type MovableCondvar = Box<Condvar>; - -unsafe impl Send for Condvar {} -unsafe impl Sync for Condvar {} - -const TIMESPEC_MAX: libc::timespec = - libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 }; - -fn saturating_cast_to_time_t(value: u64) -> libc::time_t { - if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t } -} - -impl Condvar { - pub const fn new() -> Condvar { - // Might be moved and address is changing it is better to avoid - // initialization of potentially opaque OS data before it landed - Condvar { inner: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER) } - } - - pub unsafe fn init(&mut self) { - use crate::mem::MaybeUninit; - let mut attr = MaybeUninit::<libc::pthread_condattr_t>::uninit(); - let r = libc::pthread_condattr_init(attr.as_mut_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); - assert_eq!(r, 0); - let r = libc::pthread_cond_init(self.inner.get(), attr.as_ptr()); - assert_eq!(r, 0); - let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); - assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn notify_one(&self) { - let r = libc::pthread_cond_signal(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn notify_all(&self) { - let r = libc::pthread_cond_broadcast(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - let r = libc::pthread_cond_wait(self.inner.get(), mutex::raw(mutex)); - debug_assert_eq!(r, 0); - } - - // This implementation is used on systems that support pthread_condattr_setclock - // where we configure condition variable to use monotonic clock (instead of - // default system clock). This approach avoids all problems that result - // from changes made to the system time. - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - use crate::mem; - - let mut now: libc::timespec = mem::zeroed(); - let r = libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now); - assert_eq!(r, 0); - - // Nanosecond calculations can't overflow because both values are below 1e9. - let nsec = dur.subsec_nanos() + now.tv_nsec as u32; - - let sec = saturating_cast_to_time_t(dur.as_secs()) - .checked_add((nsec / 1_000_000_000) as libc::time_t) - .and_then(|s| s.checked_add(now.tv_sec)); - let nsec = nsec % 1_000_000_000; - - let timeout = - sec.map(|s| libc::timespec { tv_sec: s, tv_nsec: nsec as _ }).unwrap_or(TIMESPEC_MAX); - - let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), &timeout); - assert!(r == libc::ETIMEDOUT || r == 0); - r == 0 - } - - #[inline] - pub unsafe fn destroy(&self) { - let r = libc::pthread_cond_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } -} diff --git a/library/std/src/sys/vxworks/ext/ffi.rs b/library/std/src/sys/vxworks/ext/ffi.rs deleted file mode 100644 index 76b34a6b5d8..00000000000 --- a/library/std/src/sys/vxworks/ext/ffi.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! Unix-specific extension to the primitives in the `std::ffi` module -//! -//! # Examples -//! -//! ``` -//! use std::ffi::OsString; -//! use std::os::unix::ffi::OsStringExt; -//! -//! let bytes = b"foo".to_vec(); -//! -//! // OsStringExt::from_vec -//! let os_string = OsString::from_vec(bytes); -//! assert_eq!(os_string.to_str(), Some("foo")); -//! -//! // OsStringExt::into_vec -//! let bytes = os_string.into_vec(); -//! assert_eq!(bytes, b"foo"); -//! ``` -//! -//! ``` -//! use std::ffi::OsStr; -//! use std::os::unix::ffi::OsStrExt; -//! -//! let bytes = b"foo"; -//! -//! // OsStrExt::from_bytes -//! let os_str = OsStr::from_bytes(bytes); -//! assert_eq!(os_str.to_str(), Some("foo")); -//! -//! // OsStrExt::as_bytes -//! let bytes = os_str.as_bytes(); -//! assert_eq!(bytes, b"foo"); -//! ``` - -#![stable(feature = "rust1", since = "1.0.0")] - -#[stable(feature = "rust1", since = "1.0.0")] -pub use crate::sys_common::os_str_bytes::*; diff --git a/library/std/src/sys/vxworks/ext/fs.rs b/library/std/src/sys/vxworks/ext/fs.rs deleted file mode 100644 index 68dc21b806c..00000000000 --- a/library/std/src/sys/vxworks/ext/fs.rs +++ /dev/null @@ -1,817 +0,0 @@ -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::fs::{self, Permissions}; -use crate::io; -use crate::path::Path; -use crate::sys; -use crate::sys::platform::fs::MetadataExt as UnixMetadataExt; -use crate::sys_common::{AsInner, AsInnerMut, FromInner}; - -/// Unix-specific extensions to [`fs::File`]. -#[stable(feature = "file_offset", since = "1.15.0")] -pub trait FileExt { - /// Reads a number of bytes starting from a given offset. - /// - /// Returns the number of bytes read. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// Note that similar to [`File::read`], it is not an error to return with a - /// short read. - /// - /// [`File::read`]: fs::File::read - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs::File; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; - /// - /// // We now read 8 bytes from the offset 10. - /// let num_bytes_read = file.read_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", num_bytes_read, buf); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; - - /// Reads the exact number of byte required to fill `buf` from the given offset. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. - /// - /// [`Read::read_exact`]: io::Read::read_exact - /// [`read_at`]: FileExt::read_at - /// - /// # Errors - /// - /// If this function encounters an error of the kind - /// [`ErrorKind::Interrupted`] then the error is ignored and the operation - /// will continue. - /// - /// If this function encounters an "end of file" before completely filling - /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`]. - /// The contents of `buf` are unspecified in this case. - /// - /// If any other read error is encountered then this function immediately - /// returns. The contents of `buf` are unspecified in this case. - /// - /// If this function returns an error, it is unspecified how many bytes it - /// has read, but it will never read more than would be necessary to - /// completely fill the buffer. - /// - /// [`ErrorKind::Interrupted`]: io::ErrorKind::Interrupted - /// [`ErrorKind::UnexpectedEof`]: io::ErrorKind::UnexpectedEof - /// - /// # Examples - /// - /// ```no_run - /// #![feature(rw_exact_all_at)] - /// use std::io; - /// use std::fs::File; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let mut buf = [0u8; 8]; - /// let file = File::open("foo.txt")?; - /// - /// // We now read exactly 8 bytes from the offset 10. - /// file.read_exact_at(&mut buf, 10)?; - /// println!("read {} bytes: {:?}", buf.len(), buf); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rw_exact_all_at", since = "1.33.0")] - fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { - while !buf.is_empty() { - match self.read_at(buf, offset) { - Ok(0) => break, - Ok(n) => { - let tmp = buf; - buf = &mut tmp[n..]; - offset += n as u64; - } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - if !buf.is_empty() { - Err(io::Error::new(io::ErrorKind::UnexpectedEof, "failed to fill whole buffer")) - } else { - Ok(()) - } - } - - /// Writes a number of bytes starting from a given offset. - /// - /// Returns the number of bytes written. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// When writing beyond the end of the file, the file is appropriately - /// extended and the intermediate bytes are initialized with the value 0. - /// - /// Note that similar to [`File::write`], it is not an error to return a - /// short write. - /// - /// [`File::write`]: fs::File::write - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::io; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let file = File::open("foo.txt")?; - /// - /// // We now write at the offset 10. - /// file.write_at(b"sushi", 10)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_offset", since = "1.15.0")] - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; - - /// Attempts to write an entire buffer starting from a given offset. - /// - /// The offset is relative to the start of the file and thus independent - /// from the current cursor. - /// - /// The current file cursor is not affected by this function. - /// - /// This method will continuously call [`write_at`] until there is no more data - /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is - /// returned. This method will not return until the entire buffer has been - /// successfully written or such an error occurs. The first error that is - /// not of [`ErrorKind::Interrupted`] kind generated from this method will be - /// returned. - /// - /// # Errors - /// - /// This function will return the first error of - /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. - /// - /// [`ErrorKind::Interrupted`]: io::ErrorKind::Interrupted - /// [`write_at`]: FileExt::write_at - /// - /// # Examples - /// - /// ```no_run - /// #![feature(rw_exact_all_at)] - /// use std::fs::File; - /// use std::io; - /// use std::os::unix::prelude::FileExt; - /// - /// fn main() -> io::Result<()> { - /// let file = File::open("foo.txt")?; - /// - /// // We now write at the offset 10. - /// file.write_all_at(b"sushi", 10)?; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "rw_exact_all_at", since = "1.33.0")] - fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { - while !buf.is_empty() { - match self.write_at(buf, offset) { - Ok(0) => { - return Err(io::Error::new( - io::ErrorKind::WriteZero, - "failed to write whole buffer", - )); - } - Ok(n) => { - buf = &buf[n..]; - offset += n as u64 - } - Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => return Err(e), - } - } - Ok(()) - } -} - -#[stable(feature = "file_offset", since = "1.15.0")] -impl FileExt for fs::File { - fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - self.as_inner().read_at(buf, offset) - } - fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - self.as_inner().write_at(buf, offset) - } -} - -/// Unix-specific extensions to [`fs::Permissions`]. -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait PermissionsExt { - /// Returns the underlying raw `st_mode` bits that contain the standard - /// Unix permissions for this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let permissions = metadata.permissions(); - /// - /// println!("permissions: {}", permissions.mode()); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&self) -> u32; - - /// Sets the underlying raw bits for this set of permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::File; - /// use std::os::unix::fs::PermissionsExt; - /// - /// fn main() -> std::io::Result<()> { - /// let f = File::create("foo.txt")?; - /// let metadata = f.metadata()?; - /// let mut permissions = metadata.permissions(); - /// - /// permissions.set_mode(0o644); // Read/write for owner and read for others. - /// assert_eq!(permissions.mode(), 0o644); - /// Ok(()) } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn set_mode(&mut self, mode: u32); - - /// Creates a new instance of `Permissions` from the given set of Unix - /// permission bits. - /// - /// # Examples - /// - /// ``` - /// use std::fs::Permissions; - /// use std::os::unix::fs::PermissionsExt; - /// - /// // Read/write for owner and read for others. - /// let permissions = Permissions::from_mode(0o644); - /// assert_eq!(permissions.mode(), 0o644); - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn from_mode(mode: u32) -> Self; -} - -#[stable(feature = "fs_ext", since = "1.1.0")] -impl PermissionsExt for Permissions { - fn mode(&self) -> u32 { - self.as_inner().mode() - } - - fn set_mode(&mut self, mode: u32) { - *self = Permissions::from_inner(FromInner::from_inner(mode)); - } - - fn from_mode(mode: u32) -> Permissions { - Permissions::from_inner(FromInner::from_inner(mode)) - } -} - -/// Unix-specific extensions to [`fs::OpenOptions`]. -#[stable(feature = "fs_ext", since = "1.1.0")] -pub trait OpenOptionsExt { - /// Sets the mode bits that a new file will be created with. - /// - /// If a new file is created as part of an `OpenOptions::open` call then this - /// specified `mode` will be used as the permission bits for the new file. - /// If no `mode` is set, the default of `0o666` will be used. - /// The operating system masks out bits with the system's `umask`, to produce - /// the final permissions. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.mode(0o644); // Give read/write for owner and read for others. - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "fs_ext", since = "1.1.0")] - fn mode(&mut self, mode: u32) -> &mut Self; - - /// Pass custom flags to the `flags` argument of `open`. - /// - /// The bits that define the access mode are masked out with `O_ACCMODE`, to - /// ensure they do not interfere with the access mode set by Rusts options. - /// - /// Custom flags can only set flags, not remove flags set by Rusts options. - /// This options overwrites any previously set custom flags. - /// - /// # Examples - /// - /// ```no_run - /// # #![feature(libc)] - /// extern crate libc; - /// use std::fs::OpenOptions; - /// use std::os::unix::fs::OpenOptionsExt; - /// - /// # fn main() { - /// let mut options = OpenOptions::new(); - /// options.write(true); - /// if cfg!(unix) { - /// options.custom_flags(libc::O_NOFOLLOW); - /// } - /// let file = options.open("foo.txt"); - /// # } - /// ``` - #[stable(feature = "open_options_ext", since = "1.10.0")] - fn custom_flags(&mut self, flags: i32) -> &mut Self; -} - -/*#[stable(feature = "fs_ext", since = "1.1.0")] -impl OpenOptionsExt for OpenOptions { - fn mode(&mut self, mode: u32) -> &mut OpenOptions { - self.as_inner_mut().mode(mode); self - } - - fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions { - self.as_inner_mut().custom_flags(flags); self - } -} -*/ - -/// Unix-specific extensions to [`fs::Metadata`]. -#[stable(feature = "metadata_ext", since = "1.1.0")] -pub trait MetadataExt { - /// Returns the ID of the device containing the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::io; - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let dev_id = meta.dev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn dev(&self) -> u64; - /// Returns the inode number. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let inode = meta.ino(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ino(&self) -> u64; - /// Returns the rights applied to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let mode = meta.mode(); - /// let user_has_write_access = mode & 0o200; - /// let user_has_read_write_access = mode & 0o600; - /// let group_has_read_access = mode & 0o040; - /// let others_have_exec_access = mode & 0o001; - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mode(&self) -> u32; - /// Returns the number of hard links pointing to this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nb_hard_links = meta.nlink(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn nlink(&self) -> u64; - /// Returns the user ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let user_id = meta.uid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn uid(&self) -> u32; - /// Returns the group ID of the owner of this file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let group_id = meta.gid(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn gid(&self) -> u32; - /// Returns the device ID of this file (if it is a special one). - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let device_id = meta.rdev(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn rdev(&self) -> u64; - /// Returns the total size of this file in bytes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let file_size = meta.size(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn size(&self) -> u64; - /// Returns the time of the last access to the file. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let last_access_time = meta.atime(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn atime(&self) -> i64; - /// Returns the time of the last access to the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_access_time = meta.atime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn mtime(&self) -> i64; - /// Returns the time of the last modification of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_modification_time = meta.mtime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn ctime(&self) -> i64; - /// Returns the time of the last status change of the file in nanoseconds. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let nano_last_status_change_time = meta.ctime_nsec(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blksize(&self) -> u64; - /// Returns the number of blocks allocated to the file, in 512-byte units. - /// - /// Please note that this may be smaller than `st_size / 512` when the file has holes. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::MetadataExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("some_file")?; - /// let blocks = meta.blocks(); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn blocks(&self) -> u64; - #[stable(feature = "metadata_ext", since = "1.1.0")] - fn attrib(&self) -> u8; -} - -#[stable(feature = "metadata_ext", since = "1.1.0")] -impl MetadataExt for fs::Metadata { - fn dev(&self) -> u64 { - self.st_dev() - } - fn ino(&self) -> u64 { - self.st_ino() - } - fn mode(&self) -> u32 { - self.st_mode() - } - fn nlink(&self) -> u64 { - self.st_nlink() - } - fn uid(&self) -> u32 { - self.st_uid() - } - fn gid(&self) -> u32 { - self.st_gid() - } - fn rdev(&self) -> u64 { - self.st_rdev() - } - fn size(&self) -> u64 { - self.st_size() - } - fn atime(&self) -> i64 { - self.st_atime() - } - fn mtime(&self) -> i64 { - self.st_mtime() - } - fn ctime(&self) -> i64 { - self.st_ctime() - } - fn blksize(&self) -> u64 { - self.st_blksize() - } - fn blocks(&self) -> u64 { - self.st_blocks() - } - fn attrib(&self) -> u8 { - self.st_attrib() - } -} - -/// Unix-specific extensions for [`fs::FileType`]. -/// -/// Adds support for special Unix file types such as block/character devices, -/// pipes, and sockets. -#[stable(feature = "file_type_ext", since = "1.5.0")] -pub trait FileTypeExt { - /// Returns whether this file type is a block device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("block_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_block_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_block_device(&self) -> bool; - /// Returns whether this file type is a char device. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("char_device_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_char_device()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_char_device(&self) -> bool; - /// Returns whether this file type is a fifo. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("fifo_file")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_fifo()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_fifo(&self) -> bool; - /// Returns whether this file type is a socket. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs; - /// use std::os::unix::fs::FileTypeExt; - /// use std::io; - /// - /// fn main() -> io::Result<()> { - /// let meta = fs::metadata("unix.socket")?; - /// let file_type = meta.file_type(); - /// assert!(file_type.is_socket()); - /// Ok(()) - /// } - /// ``` - #[stable(feature = "file_type_ext", since = "1.5.0")] - fn is_socket(&self) -> bool; -} - -#[stable(feature = "file_type_ext", since = "1.5.0")] -impl FileTypeExt for fs::FileType { - fn is_block_device(&self) -> bool { - self.as_inner().is(libc::S_IFBLK) - } - fn is_char_device(&self) -> bool { - self.as_inner().is(libc::S_IFCHR) - } - fn is_fifo(&self) -> bool { - self.as_inner().is(libc::S_IFIFO) - } - fn is_socket(&self) -> bool { - self.as_inner().is(libc::S_IFSOCK) - } -} - -/// Unix-specific extension methods for [`fs::DirEntry`]. -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -pub trait DirEntryExt { - /// Returns the underlying `d_ino` field in the contained `dirent` - /// structure. - /// - /// # Examples - /// - /// ``` - /// use std::fs; - /// use std::os::unix::fs::DirEntryExt; - /// - /// if let Ok(entries) = fs::read_dir(".") { - /// for entry in entries { - /// if let Ok(entry) = entry { - /// // Here, `entry` is a `DirEntry`. - /// println!("{:?}: {}", entry.file_name(), entry.ino()); - /// } - /// } - /// } - /// ``` - #[stable(feature = "dir_entry_ext", since = "1.1.0")] - fn ino(&self) -> u64; -} - -#[stable(feature = "dir_entry_ext", since = "1.1.0")] -impl DirEntryExt for fs::DirEntry { - fn ino(&self) -> u64 { - self.as_inner().ino() - } -} - -/// Creates a new symbolic link on the filesystem. -/// -/// The `dst` path will be a symbolic link pointing to the `src` path. -/// -/// # Examples -/// -/// ```no_run -/// use std::os::unix::fs; -/// -/// fn main() -> std::io::Result<()> { -/// fs::symlink("a.txt", "b.txt")?; -/// Ok(()) -/// } -/// ``` -#[stable(feature = "symlink", since = "1.1.0")] -pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> { - sys::fs::symlink(src.as_ref(), dst.as_ref()) -} - -/// Unix-specific extensions to [`fs::DirBuilder`]. -#[stable(feature = "dir_builder", since = "1.6.0")] -pub trait DirBuilderExt { - /// Sets the mode to create new directories with. This option defaults to - /// 0o777. - /// - /// # Examples - /// - /// ```no_run - /// use std::fs::DirBuilder; - /// use std::os::unix::fs::DirBuilderExt; - /// - /// let mut builder = DirBuilder::new(); - /// builder.mode(0o755); - /// ``` - #[stable(feature = "dir_builder", since = "1.6.0")] - fn mode(&mut self, mode: u32) -> &mut Self; -} - -#[stable(feature = "dir_builder", since = "1.6.0")] -impl DirBuilderExt for fs::DirBuilder { - fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { - self.as_inner_mut().set_mode(mode); - self - } -} diff --git a/library/std/src/sys/vxworks/ext/io.rs b/library/std/src/sys/vxworks/ext/io.rs deleted file mode 100644 index 8b5a2d12af7..00000000000 --- a/library/std/src/sys/vxworks/ext/io.rs +++ /dev/null @@ -1,208 +0,0 @@ -//! Unix-specific extensions to general I/O primitives - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::fs; -use crate::io; -use crate::net; -use crate::os::raw; -use crate::sys; -use crate::sys_common::{self, AsInner, FromInner, IntoInner}; - -/// Raw file descriptors. -#[stable(feature = "rust1", since = "1.0.0")] -pub type RawFd = raw::c_int; - -/// A trait to extract the raw unix file descriptor from an underlying -/// object. -/// -/// This is only available on unix platforms and must be imported in order -/// to call the method. Windows platforms have a corresponding `AsRawHandle` -/// and `AsRawSocket` set of traits. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait AsRawFd { - /// Extracts the raw file descriptor. - /// - /// This method does **not** pass ownership of the raw file descriptor - /// to the caller. The descriptor is only guaranteed to be valid while - /// the original object has not yet been destroyed. - #[stable(feature = "rust1", since = "1.0.0")] - fn as_raw_fd(&self) -> RawFd; -} - -/// A trait to express the ability to construct an object from a raw file -/// descriptor. -#[stable(feature = "from_raw_os", since = "1.1.0")] -pub trait FromRawFd { - /// Constructs a new instance of `Self` from the given raw file - /// descriptor. - /// - /// This function **consumes ownership** of the specified file - /// descriptor. The returned object will take responsibility for closing - /// it when the object goes out of scope. - /// - /// This function is also unsafe as the primitives currently returned - /// have the contract that they are the sole owner of the file - /// descriptor they are wrapping. Usage of this function could - /// accidentally allow violating this contract which can cause memory - /// unsafety in code that relies on it being true. - #[stable(feature = "from_raw_os", since = "1.1.0")] - unsafe fn from_raw_fd(fd: RawFd) -> Self; -} - -/// A trait to express the ability to consume an object and acquire ownership of -/// its raw file descriptor. -#[stable(feature = "into_raw_os", since = "1.4.0")] -pub trait IntoRawFd { - /// Consumes this object, returning the raw underlying file descriptor. - /// - /// This function **transfers ownership** of the underlying file descriptor - /// to the caller. Callers are then the unique owners of the file descriptor - /// and must close the descriptor once it's no longer needed. - #[stable(feature = "into_raw_os", since = "1.4.0")] - fn into_raw_fd(self) -> RawFd; -} - -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl AsRawFd for RawFd { - fn as_raw_fd(&self) -> RawFd { - *self - } -} -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl IntoRawFd for RawFd { - fn into_raw_fd(self) -> RawFd { - self - } -} -#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] -impl FromRawFd for RawFd { - unsafe fn from_raw_fd(fd: RawFd) -> RawFd { - fd - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for fs::File { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for fs::File { - unsafe fn from_raw_fd(fd: RawFd) -> fs::File { - fs::File::from_inner(sys::fs::File::from_inner(fd)) - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for fs::File { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdin { - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stdout { - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -#[stable(feature = "asraw_stdio", since = "1.21.0")] -impl AsRawFd for io::Stderr { - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StdinLock<'a> { - fn as_raw_fd(&self) -> RawFd { - libc::STDIN_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StdoutLock<'a> { - fn as_raw_fd(&self) -> RawFd { - libc::STDOUT_FILENO - } -} - -#[stable(feature = "asraw_stdio_locks", since = "1.35.0")] -impl<'a> AsRawFd for io::StderrLock<'a> { - fn as_raw_fd(&self) -> RawFd { - libc::STDERR_FILENO - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpStream { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::TcpListener { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl AsRawFd for net::UdpSocket { - fn as_raw_fd(&self) -> RawFd { - *self.as_inner().socket().as_inner() - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpStream { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream { - let socket = sys::net::Socket::from_inner(fd); - net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::TcpListener { - unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener { - let socket = sys::net::Socket::from_inner(fd); - net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket)) - } -} - -#[stable(feature = "from_raw_os", since = "1.1.0")] -impl FromRawFd for net::UdpSocket { - unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket { - let socket = sys::net::Socket::from_inner(fd); - net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket)) - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpStream { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::TcpListener { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for net::UdpSocket { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_socket().into_inner() - } -} diff --git a/library/std/src/sys/vxworks/ext/mod.rs b/library/std/src/sys/vxworks/ext/mod.rs deleted file mode 100644 index 8fa9bd9d1e2..00000000000 --- a/library/std/src/sys/vxworks/ext/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -#![stable(feature = "rust1", since = "1.0.0")] -#![allow(missing_docs)] - -pub mod ffi; -pub mod fs; -pub mod io; -pub mod process; -pub mod raw; - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod prelude { - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::ffi::{OsStrExt, OsStringExt}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::fs::{FileTypeExt, MetadataExt, OpenOptionsExt, PermissionsExt}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; - #[doc(no_inline)] - #[stable(feature = "rust1", since = "1.0.0")] - pub use super::process::ExitStatusExt; -} diff --git a/library/std/src/sys/vxworks/ext/process.rs b/library/std/src/sys/vxworks/ext/process.rs deleted file mode 100644 index 3ffa5be1b3b..00000000000 --- a/library/std/src/sys/vxworks/ext/process.rs +++ /dev/null @@ -1,229 +0,0 @@ -//! Unix-specific extensions to primitives in the `std::process` module. - -#![stable(feature = "rust1", since = "1.0.0")] - -use crate::ffi::OsStr; -use crate::io; -use crate::process; -use crate::sys; -use crate::sys::vxworks::ext::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; -use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; - -/// Unix-specific extensions to the [`process::Command`] builder. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait CommandExt { - /// Sets the child process's user ID. This translates to a - /// `setuid` call in the child process. Failure in the `setuid` - /// call will cause the spawn to fail. - #[stable(feature = "rust1", since = "1.0.0")] - fn uid(&mut self, id: u16) -> &mut process::Command; - - /// Similar to `uid`, but sets the group ID of the child process. This has - /// the same semantics as the `uid` field. - #[stable(feature = "rust1", since = "1.0.0")] - fn gid(&mut self, id: u16) -> &mut process::Command; - - /// Schedules a closure to be run just before the `exec` function is - /// invoked. - /// - /// The closure is allowed to return an I/O error whose OS error code will - /// be communicated back to the parent and returned as an error from when - /// the spawn was requested. - /// - /// Multiple closures can be registered and they will be called in order of - /// their registration. If a closure returns `Err` then no further closures - /// will be called and the spawn operation will immediately return with a - /// failure. - /// - /// # Notes and Safety - /// - /// This closure will be run in the context of the child process after a - /// `fork`. This primarily means that any modifications made to memory on - /// behalf of this closure will **not** be visible to the parent process. - /// This is often a very constrained environment where normal operations - /// like `malloc` or acquiring a mutex are not guaranteed to work (due to - /// other threads perhaps still running when the `fork` was run). - /// - /// This also means that all resources such as file descriptors and - /// memory-mapped regions got duplicated. It is your responsibility to make - /// sure that the closure does not violate library invariants by making - /// invalid use of these duplicates. - /// - /// When this closure is run, aspects such as the stdio file descriptors and - /// working directory have successfully been changed, so output to these - /// locations may not appear where intended. - #[stable(feature = "process_pre_exec", since = "1.34.0")] - unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command - where - F: FnMut() -> io::Result<()> + Send + Sync + 'static; - - /// Schedules a closure to be run just before the `exec` function is - /// invoked. - /// - /// This method is stable and usable, but it should be unsafe. To fix - /// that, it got deprecated in favor of the unsafe [`pre_exec`]. - /// - /// [`pre_exec`]: CommandExt::pre_exec - #[stable(feature = "process_exec", since = "1.15.0")] - #[rustc_deprecated(since = "1.37.0", reason = "should be unsafe, use `pre_exec` instead")] - fn before_exec<F>(&mut self, f: F) -> &mut process::Command - where - F: FnMut() -> io::Result<()> + Send + Sync + 'static, - { - unsafe { self.pre_exec(f) } - } - - /// Performs all the required setup by this `Command`, followed by calling - /// the `execvp` syscall. - /// - /// On success this function will not return, and otherwise it will return - /// an error indicating why the exec (or another part of the setup of the - /// `Command`) failed. - /// - /// `exec` not returning has the same implications as calling - /// [`process::exit`] – no destructors on the current stack or any other - /// thread’s stack will be run. Therefore, it is recommended to only call - /// `exec` at a point where it is fine to not run any destructors. Note, - /// that the `execvp` syscall independently guarantees that all memory is - /// freed and all file descriptors with the `CLOEXEC` option (set by default - /// on all file descriptors opened by the standard library) are closed. - /// - /// This function, unlike `spawn`, will **not** `fork` the process to create - /// a new child. Like spawn, however, the default behavior for the stdio - /// descriptors will be to inherited from the current process. - /// - /// - /// # Notes - /// - /// The process may be in a "broken state" if this function returns in - /// error. For example the working directory, environment variables, signal - /// handling settings, various user/group information, or aspects of stdio - /// file descriptors may have changed. If a "transactional spawn" is - /// required to gracefully handle errors it is recommended to use the - /// cross-platform `spawn` instead. - #[stable(feature = "process_exec2", since = "1.9.0")] - fn exec(&mut self) -> io::Error; - - /// Set executable argument - /// - /// Set the first process argument, `argv[0]`, to something other than the - /// default executable path. - #[stable(feature = "process_set_argv0", since = "1.45.0")] - fn arg0<S>(&mut self, arg: S) -> &mut process::Command - where - S: AsRef<OsStr>; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl CommandExt for process::Command { - fn uid(&mut self, id: u16) -> &mut process::Command { - self.as_inner_mut().uid(id); - self - } - - fn gid(&mut self, id: u16) -> &mut process::Command { - self.as_inner_mut().gid(id); - self - } - - unsafe fn pre_exec<F>(&mut self, f: F) -> &mut process::Command - where - F: FnMut() -> io::Result<()> + Send + Sync + 'static, - { - self.as_inner_mut().pre_exec(Box::new(f)); - self - } - - fn exec(&mut self) -> io::Error { - self.as_inner_mut().exec(sys::process::Stdio::Inherit) - } - - fn arg0<S>(&mut self, arg: S) -> &mut process::Command - where - S: AsRef<OsStr>, - { - self.as_inner_mut().set_arg_0(arg.as_ref()); - self - } -} - -/// Unix-specific extensions to [`process::ExitStatus`]. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait ExitStatusExt { - /// Creates a new `ExitStatus` from the raw underlying `i32` return value of - /// a process. - #[stable(feature = "exit_status_from", since = "1.12.0")] - fn from_raw(raw: i32) -> Self; - - /// If the process was terminated by a signal, returns that signal. - #[stable(feature = "rust1", since = "1.0.0")] - fn signal(&self) -> Option<i32>; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExitStatusExt for process::ExitStatus { - fn from_raw(raw: i32) -> Self { - process::ExitStatus::from_inner(From::from(raw)) - } - - fn signal(&self) -> Option<i32> { - self.as_inner().signal() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl FromRawFd for process::Stdio { - unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { - let fd = sys::fd::FileDesc::new(fd); - let io = sys::process::Stdio::Fd(fd); - process::Stdio::from_inner(io) - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdin { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStdout { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "process_extensions", since = "1.2.0")] -impl AsRawFd for process::ChildStderr { - fn as_raw_fd(&self) -> RawFd { - self.as_inner().fd().raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdin { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStdout { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -#[stable(feature = "into_raw_os", since = "1.4.0")] -impl IntoRawFd for process::ChildStderr { - fn into_raw_fd(self) -> RawFd { - self.into_inner().into_fd().into_raw() - } -} - -/// Returns the OS-assigned process identifier associated with this process's parent. -#[stable(feature = "unix_ppid", since = "1.27.0")] -pub fn parent_id() -> u32 { - crate::sys::os::getppid() -} diff --git a/library/std/src/sys/vxworks/ext/raw.rs b/library/std/src/sys/vxworks/ext/raw.rs deleted file mode 100644 index 1f134f4e2d1..00000000000 --- a/library/std/src/sys/vxworks/ext/raw.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![stable(feature = "raw_ext", since = "1.1.0")] - -#[doc(inline)] -#[stable(feature = "pthread_t", since = "1.8.0")] -pub use crate::sys::platform::raw::pthread_t; diff --git a/library/std/src/sys/vxworks/fd.rs b/library/std/src/sys/vxworks/fd.rs deleted file mode 100644 index d58468ad539..00000000000 --- a/library/std/src/sys/vxworks/fd.rs +++ /dev/null @@ -1,201 +0,0 @@ -#![unstable(reason = "not public", issue = "none", feature = "fd")] - -use crate::cmp; -use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; -use crate::mem; -use crate::sys::cvt; -use crate::sys_common::AsInner; - -use libc::{self, c_int, c_void, ssize_t}; - -#[derive(Debug)] -pub struct FileDesc { - fd: c_int, -} - -// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`, -// with the man page quoting that if the count of bytes to read is -// greater than `SSIZE_MAX` the result is "unspecified". -const READ_LIMIT: usize = ssize_t::MAX as usize; - -impl FileDesc { - pub fn new(fd: c_int) -> FileDesc { - FileDesc { fd: fd } - } - - pub fn raw(&self) -> c_int { - self.fd - } - - /// Extracts the actual file descriptor without closing it. - pub fn into_raw(self) -> c_int { - let fd = self.fd; - mem::forget(self); - fd - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT)) - })?; - Ok(ret as usize) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::readv( - self.fd, - bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, - ) - })?; - Ok(ret as usize) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - true - } - - pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { - let mut me = self; - (&mut me).read_to_end(buf) - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - unsafe fn cvt_pread( - fd: c_int, - buf: *mut c_void, - count: usize, - offset: i64, - ) -> io::Result<isize> { - use libc::pread; - cvt(pread(fd, buf, count, offset)) - } - - unsafe { - cvt_pread( - self.fd, - buf.as_mut_ptr() as *mut c_void, - cmp::min(buf.len(), READ_LIMIT), - offset as i64, - ) - .map(|n| n as usize) - } - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT)) - })?; - Ok(ret as usize) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::writev( - self.fd, - bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, - ) - })?; - Ok(ret as usize) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - true - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - unsafe fn cvt_pwrite( - fd: c_int, - buf: *const c_void, - count: usize, - offset: i64, - ) -> io::Result<isize> { - use libc::pwrite; - cvt(pwrite(fd, buf, count, offset)) - } - - unsafe { - cvt_pwrite( - self.fd, - buf.as_ptr() as *const c_void, - cmp::min(buf.len(), READ_LIMIT), - offset as i64, - ) - .map(|n| n as usize) - } - } - - pub fn get_cloexec(&self) -> io::Result<bool> { - unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) } - } - - pub fn set_cloexec(&self) -> io::Result<()> { - unsafe { - let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?; - let new = previous | libc::FD_CLOEXEC; - if new != previous { - cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?; - } - Ok(()) - } - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let v = nonblocking as c_int; - cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?; - Ok(()) - } - } - - // refer to pxPipeDrv library documentation. - // VxWorks uses fcntl to set O_NONBLOCK to the pipes - pub fn set_nonblocking_pipe(&self, nonblocking: bool) -> io::Result<()> { - unsafe { - let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; - flags = if nonblocking { flags | libc::O_NONBLOCK } else { flags & !libc::O_NONBLOCK }; - cvt(libc::fcntl(self.fd, libc::F_SETFL, flags))?; - Ok(()) - } - } - - pub fn duplicate(&self) -> io::Result<FileDesc> { - let fd = self.raw(); - match cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD_CLOEXEC, 0) }) { - Ok(newfd) => Ok(FileDesc::new(newfd)), - Err(e) => return Err(e), - } - } -} - -impl<'a> Read for &'a FileDesc { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - (**self).read(buf) - } - - #[inline] - unsafe fn initializer(&self) -> Initializer { - Initializer::nop() - } -} - -impl AsInner<c_int> for FileDesc { - fn as_inner(&self) -> &c_int { - &self.fd - } -} - -impl Drop for FileDesc { - fn drop(&mut self) { - // Note that errors are ignored when closing a file descriptor. The - // reason for this is that if an error occurs we don't actually know if - // the file descriptor was closed or not, and if we retried (for - // something like EINTR), we might close another valid file descriptor - // (opened after we closed ours. - let _ = unsafe { libc::close(self.fd) }; - } -} diff --git a/library/std/src/sys/vxworks/fs.rs b/library/std/src/sys/vxworks/fs.rs deleted file mode 100644 index cb761af1a25..00000000000 --- a/library/std/src/sys/vxworks/fs.rs +++ /dev/null @@ -1,624 +0,0 @@ -// copies from linuxx -use crate::ffi::{CStr, CString, OsStr, OsString}; -use crate::fmt; -use crate::io::{self, Error, ErrorKind, IoSlice, IoSliceMut, SeekFrom}; -use crate::mem; -use crate::path::{Path, PathBuf}; -use crate::ptr; -use crate::sync::Arc; -use crate::sys::fd::FileDesc; -use crate::sys::time::SystemTime; -use crate::sys::vxworks::ext::ffi::OsStrExt; -use crate::sys::vxworks::ext::ffi::OsStringExt; -use crate::sys::{cvt, cvt_r}; -use crate::sys_common::{AsInner, FromInner}; -use libc::{self, c_int, mode_t, off_t, stat64}; -use libc::{dirent, ftruncate, lseek, open, readdir_r as readdir64_r}; -pub struct File(FileDesc); - -#[derive(Clone)] -pub struct FileAttr { - stat: stat64, -} - -// all DirEntry's will have a reference to this struct -struct InnerReadDir { - dirp: Dir, - root: PathBuf, -} - -pub struct ReadDir { - inner: Arc<InnerReadDir>, - end_of_stream: bool, -} - -struct Dir(*mut libc::DIR); - -unsafe impl Send for Dir {} -unsafe impl Sync for Dir {} - -pub struct DirEntry { - entry: dirent, - dir: Arc<InnerReadDir>, -} - -#[derive(Clone, Debug)] -pub struct OpenOptions { - // generic - read: bool, - write: bool, - append: bool, - truncate: bool, - create: bool, - create_new: bool, - // system-specific - custom_flags: i32, - mode: mode_t, -} - -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { - mode: mode_t, -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType { - mode: mode_t, -} - -#[derive(Debug)] -pub struct DirBuilder { - mode: mode_t, -} - -impl FileAttr { - pub fn size(&self) -> u64 { - self.stat.st_size as u64 - } - pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat.st_mode as mode_t) } - } - - pub fn file_type(&self) -> FileType { - FileType { mode: self.stat.st_mode as mode_t } - } - - pub fn modified(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: 0, // hack 2.0; - })) - } - - pub fn accessed(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: 0, // hack - a proper fix would be better - })) - } - - pub fn created(&self) -> io::Result<SystemTime> { - Err(io::Error::new( - io::ErrorKind::Other, - "creation time is not available on this platform currently", - )) - } -} - -impl AsInner<stat64> for FileAttr { - fn as_inner(&self) -> &stat64 { - &self.stat - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - // check if any class (owner, group, others) has write permission - self.mode & 0o222 == 0 - } - - pub fn set_readonly(&mut self, readonly: bool) { - if readonly { - // remove write permission for all classes; equivalent to `chmod a-w <file>` - self.mode &= !0o222; - } else { - // add write permission for all classes; equivalent to `chmod a+w <file>` - self.mode |= 0o222; - } - } - pub fn mode(&self) -> u32 { - self.mode as u32 - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - self.is(libc::S_IFDIR) - } - pub fn is_file(&self) -> bool { - self.is(libc::S_IFREG) - } - pub fn is_symlink(&self) -> bool { - self.is(libc::S_IFLNK) - } - - pub fn is(&self, mode: mode_t) -> bool { - self.mode & libc::S_IFMT == mode - } -} - -impl FromInner<u32> for FilePermissions { - fn from_inner(mode: u32) -> FilePermissions { - FilePermissions { mode: mode as mode_t } - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. - // Thus the result will be e g 'ReadDir("/home")' - fmt::Debug::fmt(&*self.inner.root, f) - } -} - -impl Iterator for ReadDir { - type Item = io::Result<DirEntry>; - fn next(&mut self) -> Option<io::Result<DirEntry>> { - if self.end_of_stream { - return None; - } - - unsafe { - let mut ret = DirEntry { entry: mem::zeroed(), dir: Arc::clone(&self.inner) }; - let mut entry_ptr = ptr::null_mut(); - loop { - if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 { - if entry_ptr.is_null() { - // We encountered an error (which will be returned in this iteration), but - // we also reached the end of the directory stream. The `end_of_stream` - // flag is enabled to make sure that we return `None` in the next iteration - // (instead of looping forever) - self.end_of_stream = true; - } - return Some(Err(Error::last_os_error())); - } - if entry_ptr.is_null() { - return None; - } - if ret.name_bytes() != b"." && ret.name_bytes() != b".." { - return Some(Ok(ret)); - } - } - } - } -} - -impl Drop for Dir { - fn drop(&mut self) { - let r = unsafe { libc::closedir(self.0) }; - debug_assert_eq!(r, 0); - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - use crate::sys::vxworks::ext::ffi::OsStrExt; - self.dir.root.join(OsStr::from_bytes(self.name_bytes())) - } - - pub fn file_name(&self) -> OsString { - OsStr::from_bytes(self.name_bytes()).to_os_string() - } - - pub fn metadata(&self) -> io::Result<FileAttr> { - lstat(&self.path()) - } - - pub fn file_type(&self) -> io::Result<FileType> { - lstat(&self.path()).map(|m| m.file_type()) - } - - pub fn ino(&self) -> u64 { - self.entry.d_ino as u64 - } - - fn name_bytes(&self) -> &[u8] { - unsafe { - //&*self.name - CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() - } - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions { - // generic - read: false, - write: false, - append: false, - truncate: false, - create: false, - create_new: false, - // system-specific - custom_flags: 0, - mode: 0o666, - } - } - - pub fn read(&mut self, read: bool) { - self.read = read; - } - pub fn write(&mut self, write: bool) { - self.write = write; - } - pub fn append(&mut self, append: bool) { - self.append = append; - } - pub fn truncate(&mut self, truncate: bool) { - self.truncate = truncate; - } - pub fn create(&mut self, create: bool) { - self.create = create; - } - pub fn create_new(&mut self, create_new: bool) { - self.create_new = create_new; - } - pub fn mode(&mut self, mode: u32) { - self.mode = mode as mode_t; - } - - fn get_access_mode(&self) -> io::Result<c_int> { - match (self.read, self.write, self.append) { - (true, false, false) => Ok(libc::O_RDONLY), - (false, true, false) => Ok(libc::O_WRONLY), - (true, true, false) => Ok(libc::O_RDWR), - (false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND), - (true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND), - (false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)), - } - } - - fn get_creation_mode(&self) -> io::Result<c_int> { - match (self.write, self.append) { - (true, false) => {} - (false, false) => { - if self.truncate || self.create || self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - } - } - (_, true) => { - if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); - } - } - } - - Ok(match (self.create, self.truncate, self.create_new) { - (false, false, false) => 0, - (true, false, false) => libc::O_CREAT, - (false, true, false) => libc::O_TRUNC, - (true, true, false) => libc::O_CREAT | libc::O_TRUNC, - (_, _, true) => libc::O_CREAT | libc::O_EXCL, - }) - } -} - -impl File { - pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> { - let path = cstr(path)?; - File::open_c(&path, opts) - } - - pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> { - let flags = libc::O_CLOEXEC - | opts.get_access_mode()? - | opts.get_creation_mode()? - | (opts.custom_flags as c_int & !libc::O_ACCMODE); - let fd = cvt_r(|| unsafe { open(path.as_ptr(), flags, opts.mode as c_int) })?; - Ok(File(FileDesc::new(fd))) - } - - pub fn file_attr(&self) -> io::Result<FileAttr> { - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { ::libc::fstat(self.0.raw(), &mut stat) })?; - Ok(FileAttr { stat: stat }) - } - - pub fn fsync(&self) -> io::Result<()> { - cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?; - Ok(()) - } - - pub fn datasync(&self) -> io::Result<()> { - cvt_r(|| unsafe { os_datasync(self.0.raw()) })?; - return Ok(()); - unsafe fn os_datasync(fd: c_int) -> c_int { - libc::fsync(fd) - } //not supported - } - - pub fn truncate(&self, size: u64) -> io::Result<()> { - return cvt_r(|| unsafe { ftruncate(self.0.raw(), size as off_t) }).map(drop); - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.0.read(buf) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { - self.0.read_at(buf, offset) - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { - self.0.write_at(buf, offset) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } - - pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { - let (whence, pos) = match pos { - // Casting to `i64` is fine, too large values will end up as - // negative which will cause an error in `"lseek64"`. - SeekFrom::Start(off) => (libc::SEEK_SET, off as i64), - SeekFrom::End(off) => (libc::SEEK_END, off), - SeekFrom::Current(off) => (libc::SEEK_CUR, off), - }; - let n = cvt(unsafe { lseek(self.0.raw(), pos, whence) })?; - Ok(n as u64) - } - - pub fn duplicate(&self) -> io::Result<File> { - self.0.duplicate().map(File) - } - - pub fn fd(&self) -> &FileDesc { - &self.0 - } - - pub fn into_fd(self) -> FileDesc { - self.0 - } - - pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { - cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?; - Ok(()) - } - - pub fn diverge(&self) -> ! { - panic!() - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder { mode: 0o777 } - } - - pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?; - Ok(()) - } - - pub fn set_mode(&mut self, mode: u32) { - self.mode = mode as mode_t; - } -} - -fn cstr(path: &Path) -> io::Result<CString> { - use crate::sys::vxworks::ext::ffi::OsStrExt; - Ok(CString::new(path.as_os_str().as_bytes())?) -} - -impl FromInner<c_int> for File { - fn from_inner(fd: c_int) -> File { - File(FileDesc::new(fd)) - } -} - -impl fmt::Debug for File { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fn get_path(fd: c_int) -> Option<PathBuf> { - let mut buf = vec![0; libc::PATH_MAX as usize]; - let n = unsafe { libc::ioctl(fd, libc::FIOGETNAME, buf.as_ptr()) }; - if n == -1 { - return None; - } - let l = buf.iter().position(|&c| c == 0).unwrap(); - buf.truncate(l as usize); - Some(PathBuf::from(OsString::from_vec(buf))) - } - fn get_mode(fd: c_int) -> Option<(bool, bool)> { - let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; - if mode == -1 { - return None; - } - match mode & libc::O_ACCMODE { - libc::O_RDONLY => Some((true, false)), - libc::O_RDWR => Some((true, true)), - libc::O_WRONLY => Some((false, true)), - _ => None, - } - } - - let fd = self.0.raw(); - let mut b = f.debug_struct("File"); - b.field("fd", &fd); - if let Some(path) = get_path(fd) { - b.field("path", &path); - } - if let Some((read, write)) = get_mode(fd) { - b.field("read", &read).field("write", &write); - } - b.finish() - } -} - -pub fn readdir(p: &Path) -> io::Result<ReadDir> { - let root = p.to_path_buf(); - let p = cstr(p)?; - unsafe { - let ptr = libc::opendir(p.as_ptr()); - if ptr.is_null() { - Err(Error::last_os_error()) - } else { - let inner = InnerReadDir { dirp: Dir(ptr), root }; - Ok(ReadDir { inner: Arc::new(inner), end_of_stream: false }) - } - } -} - -pub fn unlink(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::unlink(p.as_ptr()) })?; - Ok(()) -} - -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = cstr(old)?; - let new = cstr(new)?; - cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })?; - Ok(()) -} - -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = cstr(p)?; - cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })?; - Ok(()) -} - -pub fn rmdir(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::rmdir(p.as_ptr()) })?; - Ok(()) -} - -pub fn remove_dir_all(path: &Path) -> io::Result<()> { - let filetype = lstat(path)?.file_type(); - if filetype.is_symlink() { unlink(path) } else { remove_dir_all_recursive(path) } -} - -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { - for child in readdir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - unlink(&child.path())?; - } - } - rmdir(path) -} - -pub fn readlink(p: &Path) -> io::Result<PathBuf> { - let c_path = cstr(p)?; - let p = c_path.as_ptr(); - - let mut buf = Vec::with_capacity(256); - - loop { - let buf_read = - cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? as usize; - - unsafe { - buf.set_len(buf_read); - } - - if buf_read != buf.capacity() { - buf.shrink_to_fit(); - - return Ok(PathBuf::from(OsString::from_vec(buf))); - } - - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. The length is guaranteed to be - // the same as the capacity due to the if statement above. - buf.reserve(1); - } -} - -pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })?; - Ok(()) -} - -pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src)?; - let dst = cstr(dst)?; - cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })?; - Ok(()) -} - -pub fn stat(p: &Path) -> io::Result<FileAttr> { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { libc::stat(p.as_ptr(), &mut stat as *mut _ as *mut _) })?; - Ok(FileAttr { stat }) -} - -pub fn lstat(p: &Path) -> io::Result<FileAttr> { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { ::libc::lstat(p.as_ptr(), &mut stat as *mut _ as *mut _) })?; - Ok(FileAttr { stat }) -} - -pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { - use crate::sys::vxworks::ext::ffi::OsStrExt; - let path = CString::new(p.as_os_str().as_bytes())?; - let buf; - unsafe { - let r = libc::realpath(path.as_ptr(), ptr::null_mut()); - if r.is_null() { - return Err(io::Error::last_os_error()); - } - buf = CStr::from_ptr(r).to_bytes().to_vec(); - libc::free(r as *mut _); - } - Ok(PathBuf::from(OsString::from_vec(buf))) -} - -pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { - use crate::fs::File; - if !from.is_file() { - return Err(Error::new( - ErrorKind::InvalidInput, - "the source path is not an existing regular file", - )); - } - - let mut reader = File::open(from)?; - let mut writer = File::create(to)?; - let perm = reader.metadata()?.permissions(); - - let ret = io::copy(&mut reader, &mut writer)?; - writer.set_permissions(perm)?; - Ok(ret) -} diff --git a/library/std/src/sys/vxworks/io.rs b/library/std/src/sys/vxworks/io.rs deleted file mode 100644 index 0f68ebf8da9..00000000000 --- a/library/std/src/sys/vxworks/io.rs +++ /dev/null @@ -1,75 +0,0 @@ -use crate::marker::PhantomData; -use crate::slice; - -use libc::{c_void, iovec}; - -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct IoSlice<'a> { - vec: iovec, - _p: PhantomData<&'a [u8]>, -} - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice { - vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { - panic!("advancing IoSlice beyond its length"); - } - - unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } -} - -pub struct IoSliceMut<'a> { - vec: iovec, - _p: PhantomData<&'a mut [u8]>, -} - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut { - vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if self.vec.iov_len < n { - panic!("advancing IoSliceMut beyond its length"); - } - - unsafe { - self.vec.iov_len -= n; - self.vec.iov_base = self.vec.iov_base.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } - } -} diff --git a/library/std/src/sys/vxworks/memchr.rs b/library/std/src/sys/vxworks/memchr.rs deleted file mode 100644 index 928100c92ff..00000000000 --- a/library/std/src/sys/vxworks/memchr.rs +++ /dev/null @@ -1,21 +0,0 @@ -// Original implementation taken from rust-memchr. -// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch - -pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { - let p = unsafe { - libc::memchr( - haystack.as_ptr() as *const libc::c_void, - needle as libc::c_int, - haystack.len(), - ) - }; - if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) } -} - -pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> { - fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> { - core::slice::memchr::memrchr(needle, haystack) - } - - memrchr_specific(needle, haystack) -} diff --git a/library/std/src/sys/vxworks/mod.rs b/library/std/src/sys/vxworks/mod.rs index 1132a849e2f..c20edaa1a47 100644 --- a/library/std/src/sys/vxworks/mod.rs +++ b/library/std/src/sys/vxworks/mod.rs @@ -7,29 +7,53 @@ pub use self::rand::hashmap_random_keys; pub use crate::os::vxworks as platform; pub use libc::strlen; +#[macro_use] +#[path = "../unix/weak.rs"] +pub mod weak; + +#[path = "../unix/alloc.rs"] pub mod alloc; +#[path = "../unix/args.rs"] pub mod args; +#[path = "../unix/cmath.rs"] pub mod cmath; +#[path = "../unix/condvar.rs"] pub mod condvar; pub mod env; +#[path = "../unix/ext/mod.rs"] pub mod ext; +#[path = "../unix/fd.rs"] pub mod fd; +#[path = "../unix/fs.rs"] pub mod fs; +#[path = "../unix/io.rs"] pub mod io; +#[path = "../unix/memchr.rs"] pub mod memchr; +#[path = "../unix/mutex.rs"] pub mod mutex; +#[path = "../unix/net.rs"] pub mod net; +#[path = "../unix/os.rs"] pub mod os; +#[path = "../unix/path.rs"] pub mod path; +#[path = "../unix/pipe.rs"] pub mod pipe; pub mod process; pub mod rand; +#[path = "../unix/rwlock.rs"] pub mod rwlock; +#[path = "../unix/stack_overflow.rs"] pub mod stack_overflow; +#[path = "../unix/stdio.rs"] pub mod stdio; +#[path = "../unix/thread.rs"] pub mod thread; pub mod thread_local_dtor; +#[path = "../unix/thread_local_key.rs"] pub mod thread_local_key; +#[path = "../unix/time.rs"] pub mod time; pub use crate::sys_common::os_str_bytes as os_str; diff --git a/library/std/src/sys/vxworks/mutex.rs b/library/std/src/sys/vxworks/mutex.rs deleted file mode 100644 index dd7582c21a7..00000000000 --- a/library/std/src/sys/vxworks/mutex.rs +++ /dev/null @@ -1,133 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::mem::MaybeUninit; - -pub struct Mutex { - inner: UnsafeCell<libc::pthread_mutex_t>, -} - -pub type MovableMutex = Box<Mutex>; - -#[inline] -pub unsafe fn raw(m: &Mutex) -> *mut libc::pthread_mutex_t { - m.inner.get() -} - -unsafe impl Send for Mutex {} -unsafe impl Sync for Mutex {} - -#[allow(dead_code)] // sys isn't exported yet -impl Mutex { - pub const fn new() -> Mutex { - // Might be moved to a different address, so it is better to avoid - // initialization of potentially opaque OS data before it landed. - // Be very careful using this newly constructed `Mutex`, reentrant - // locking is undefined behavior until `init` is called! - Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } - } - #[inline] - pub unsafe fn init(&mut self) { - // Issue #33770 - // - // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have - // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you - // try to re-lock it from the same thread when you already hold a lock. - // - // In practice, glibc takes advantage of this undefined behavior to - // implement hardware lock elision, which uses hardware transactional - // memory to avoid acquiring the lock. While a transaction is in - // progress, the lock appears to be unlocked. This isn't a problem for - // other threads since the transactional memory will abort if a conflict - // is detected, however no abort is generated if re-locking from the - // same thread. - // - // Since locking the same mutex twice will result in two aliasing &mut - // references, we instead create the mutex with type - // PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to - // re-lock it from the same thread, thus avoiding undefined behavior. - let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); - let r = libc::pthread_mutexattr_init(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_NORMAL); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn lock(&self) { - let r = libc::pthread_mutex_lock(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn unlock(&self) { - let r = libc::pthread_mutex_unlock(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(self.inner.get()) == 0 - } - #[inline] - #[cfg(not(target_os = "dragonfly"))] - pub unsafe fn destroy(&self) { - let r = libc::pthread_mutex_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } - #[inline] - #[cfg(target_os = "dragonfly")] - pub unsafe fn destroy(&self) { - let r = libc::pthread_mutex_destroy(self.inner.get()); - // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a - // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. - // Once it is used (locked/unlocked) or pthread_mutex_init() is called, - // this behaviour no longer occurs. - debug_assert!(r == 0 || r == libc::EINVAL); - } -} - -pub struct ReentrantMutex { - inner: UnsafeCell<libc::pthread_mutex_t>, -} - -unsafe impl Send for ReentrantMutex {} -unsafe impl Sync for ReentrantMutex {} - -impl ReentrantMutex { - pub const unsafe fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } - } - - pub unsafe fn init(&self) { - let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); - let result = libc::pthread_mutexattr_init(attr.as_mut_ptr()); - debug_assert_eq!(result, 0); - let result = - libc::pthread_mutexattr_settype(attr.as_mut_ptr(), libc::PTHREAD_MUTEX_RECURSIVE); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutex_init(self.inner.get(), attr.as_ptr()); - debug_assert_eq!(result, 0); - let result = libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(result, 0); - } - - pub unsafe fn lock(&self) { - let result = libc::pthread_mutex_lock(self.inner.get()); - debug_assert_eq!(result, 0); - } - - #[inline] - pub unsafe fn try_lock(&self) -> bool { - libc::pthread_mutex_trylock(self.inner.get()) == 0 - } - - pub unsafe fn unlock(&self) { - let result = libc::pthread_mutex_unlock(self.inner.get()); - debug_assert_eq!(result, 0); - } - - pub unsafe fn destroy(&self) { - let result = libc::pthread_mutex_destroy(self.inner.get()); - debug_assert_eq!(result, 0); - } -} diff --git a/library/std/src/sys/vxworks/net.rs b/library/std/src/sys/vxworks/net.rs deleted file mode 100644 index 7613fbec46f..00000000000 --- a/library/std/src/sys/vxworks/net.rs +++ /dev/null @@ -1,335 +0,0 @@ -#[cfg(all(test, taget_env = "gnu"))] -mod tests; - -use crate::cmp; -use crate::ffi::CStr; -use crate::io; -use crate::io::{IoSlice, IoSliceMut}; -use crate::mem; -use crate::net::{Shutdown, SocketAddr}; -use crate::str; -use crate::sys::fd::FileDesc; -use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr}; -use crate::sys_common::{AsInner, FromInner, IntoInner}; -use crate::time::{Duration, Instant}; -use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK}; - -pub use crate::sys::{cvt, cvt_r}; - -#[allow(unused_extern_crates)] -pub extern crate libc as netc; - -pub type wrlen_t = size_t; - -pub struct Socket(FileDesc); - -pub fn init() {} - -pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { - return Ok(()); - } - - // We may need to trigger a glibc workaround. See on_resolver_failure() for details. - on_resolver_failure(); - - if err == EAI_SYSTEM { - return Err(io::Error::last_os_error()); - } - - let detail = unsafe { - str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap().to_owned() - }; - Err(io::Error::new( - io::ErrorKind::Other, - &format!("failed to lookup address information: {}", detail)[..], - )) -} - -impl Socket { - pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> { - let fam = match *addr { - SocketAddr::V4(..) => libc::AF_INET, - SocketAddr::V6(..) => libc::AF_INET6, - }; - Socket::new_raw(fam, ty) - } - - pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> { - unsafe { - let fd = cvt(libc::socket(fam, ty, 0))?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - let socket = Socket(fd); - Ok(socket) - } - } - - pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> { - unimplemented!(); - } - - pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> { - self.set_nonblocking(true)?; - let r = unsafe { - let (addrp, len) = addr.into_inner(); - cvt(libc::connect(self.0.raw(), addrp, len)) - }; - self.set_nonblocking(false)?; - - match r { - Ok(_) => return Ok(()), - // there's no ErrorKind for EINPROGRESS :( - Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {} - Err(e) => return Err(e), - } - - let mut pollfd = libc::pollfd { fd: self.0.raw(), events: libc::POLLOUT, revents: 0 }; - - if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - - let start = Instant::now(); - - loop { - let elapsed = start.elapsed(); - if elapsed >= timeout { - return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out")); - } - - let timeout = timeout - elapsed; - let mut timeout = timeout - .as_secs() - .saturating_mul(1_000) - .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000); - if timeout == 0 { - timeout = 1; - } - - let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; - - match unsafe { libc::poll(&mut pollfd, 1, timeout) } { - -1 => { - let err = io::Error::last_os_error(); - if err.kind() != io::ErrorKind::Interrupted { - return Err(err); - } - } - 0 => {} - _ => { - // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look - // for POLLHUP rather than read readiness - if pollfd.revents & libc::POLLHUP != 0 { - let e = self.take_error()?.unwrap_or_else(|| { - io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") - }); - return Err(e); - } - - return Ok(()); - } - } - } - } - - pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> { - let fd = cvt_r(|| unsafe { libc::accept(self.0.raw(), storage, len) })?; - let fd = FileDesc::new(fd); - fd.set_cloexec()?; - Ok(Socket(fd)) - } - - pub fn duplicate(&self) -> io::Result<Socket> { - self.0.duplicate().map(Socket) - } - - fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { - let ret = cvt(unsafe { - libc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags) - })?; - Ok(ret as usize) - } - - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.recv_with_flags(buf, 0) - } - - pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { - self.recv_with_flags(buf, MSG_PEEK) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - fn recv_from_with_flags( - &self, - buf: &mut [u8], - flags: c_int, - ) -> io::Result<(usize, SocketAddr)> { - let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; - let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t; - - let n = cvt(unsafe { - libc::recvfrom( - self.0.raw(), - buf.as_mut_ptr() as *mut c_void, - buf.len(), - flags, - &mut storage as *mut _ as *mut _, - &mut addrlen, - ) - })?; - Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?)) - } - - pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, 0) - } - - pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - self.recv_from_with_flags(buf, MSG_PEEK) - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> { - let timeout = match dur { - Some(dur) => { - if dur.as_secs() == 0 && dur.subsec_nanos() == 0 { - return Err(io::Error::new( - io::ErrorKind::InvalidInput, - "cannot set a 0 duration timeout", - )); - } - - let secs = if dur.as_secs() > libc::time_t::MAX as u64 { - libc::time_t::MAX - } else { - dur.as_secs() as libc::time_t - }; - let mut timeout = libc::timeval { - tv_sec: secs, - tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, - }; - if timeout.tv_sec == 0 && timeout.tv_usec == 0 { - timeout.tv_usec = 1; - } - timeout - } - None => libc::timeval { tv_sec: 0, tv_usec: 0 }, - }; - setsockopt(self, libc::SOL_SOCKET, kind, timeout) - } - - pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> { - let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?; - if raw.tv_sec == 0 && raw.tv_usec == 0 { - Ok(None) - } else { - let sec = raw.tv_sec as u64; - let nsec = (raw.tv_usec as u32) * 1000; - Ok(Some(Duration::new(sec, nsec))) - } - } - - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { - let how = match how { - Shutdown::Write => libc::SHUT_WR, - Shutdown::Read => libc::SHUT_RD, - Shutdown::Both => libc::SHUT_RDWR, - }; - cvt(unsafe { libc::shutdown(self.0.raw(), how) })?; - Ok(()) - } - - pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { - setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int) - } - - pub fn nodelay(&self) -> io::Result<bool> { - let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?; - Ok(raw != 0) - } - - pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut nonblocking = nonblocking as libc::c_int; - cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop) - } - - pub fn take_error(&self) -> io::Result<Option<io::Error>> { - let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; - if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } - } -} - -impl AsInner<c_int> for Socket { - fn as_inner(&self) -> &c_int { - self.0.as_inner() - } -} - -impl FromInner<c_int> for Socket { - fn from_inner(fd: c_int) -> Socket { - Socket(FileDesc::new(fd)) - } -} - -impl IntoInner<c_int> for Socket { - fn into_inner(self) -> c_int { - self.0.into_raw() - } -} - -// In versions of glibc prior to 2.26, there's a bug where the DNS resolver -// will cache the contents of /etc/resolv.conf, so changes to that file on disk -// can be ignored by a long-running program. That can break DNS lookups on e.g. -// laptops where the network comes and goes. See -// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some -// distros including Debian have patched glibc to fix this for a long time. -// -// A workaround for this bug is to call the res_init libc function, to clear -// the cached configs. Unfortunately, while we believe glibc's implementation -// of res_init is thread-safe, we know that other implementations are not -// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could -// try to synchronize its res_init calls with a Mutex, but that wouldn't -// protect programs that call into libc in other ways. So instead of calling -// res_init unconditionally, we call it only when we detect we're linking -// against glibc version < 2.26. (That is, when we both know its needed and -// believe it's thread-safe). -#[cfg(target_env = "gnu")] -fn on_resolver_failure() { - /* - use crate::sys; - - // If the version fails to parse, we treat it the same as "not glibc". - if let Some(version) = sys::os::glibc_version() { - if version < (2, 26) { - unsafe { libc::res_init() }; - } - } - */ -} - -#[cfg(not(target_env = "gnu"))] -fn on_resolver_failure() {} diff --git a/library/std/src/sys/vxworks/net/tests.rs b/library/std/src/sys/vxworks/net/tests.rs deleted file mode 100644 index e7c6e348f8e..00000000000 --- a/library/std/src/sys/vxworks/net/tests.rs +++ /dev/null @@ -1,23 +0,0 @@ -use super::*; - -#[test] -fn test_res_init() { - // This mostly just tests that the weak linkage doesn't panic wildly... - res_init_if_glibc_before_2_26().unwrap(); -} - -#[test] -fn test_parse_glibc_version() { - let cases = [ - ("0.0", Some((0, 0))), - ("01.+2", Some((1, 2))), - ("3.4.5.six", Some((3, 4))), - ("1", None), - ("1.-2", None), - ("1.foo", None), - ("foo.1", None), - ]; - for &(version_str, parsed) in cases.iter() { - assert_eq!(parsed, parse_glibc_version(version_str)); - } -} diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs deleted file mode 100644 index 08394a8d29d..00000000000 --- a/library/std/src/sys/vxworks/os.rs +++ /dev/null @@ -1,315 +0,0 @@ -use crate::error::Error as StdError; -use crate::ffi::{CStr, CString, OsStr, OsString}; -use crate::fmt; -use crate::io; -use crate::iter; -use crate::marker::PhantomData; -use crate::mem; -use crate::memchr; -use crate::path::{self, Path, PathBuf}; -use crate::slice; -use crate::str; -use crate::sys::cvt; -use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; -use libc::{self, c_char /*,c_void */, c_int}; -/*use sys::fd; this one is probably important */ -use crate::vec; - -const TMPBUF_SZ: usize = 128; - -// This is a terrible fix -use crate::sys::os_str::Buf; -use crate::sys_common::{AsInner, FromInner, IntoInner}; - -pub trait OsStringExt { - fn from_vec(vec: Vec<u8>) -> Self; - fn into_vec(self) -> Vec<u8>; -} - -impl OsStringExt for OsString { - fn from_vec(vec: Vec<u8>) -> OsString { - FromInner::from_inner(Buf { inner: vec }) - } - fn into_vec(self) -> Vec<u8> { - self.into_inner().inner - } -} - -pub trait OsStrExt { - fn from_bytes(slice: &[u8]) -> &Self; - fn as_bytes(&self) -> &[u8]; -} - -impl OsStrExt for OsStr { - fn from_bytes(slice: &[u8]) -> &OsStr { - unsafe { mem::transmute(slice) } - } - fn as_bytes(&self) -> &[u8] { - &self.as_inner().inner - } -} - -pub fn errno() -> i32 { - unsafe { libc::errnoGet() } -} - -pub fn set_errno(e: i32) { - unsafe { - libc::errnoSet(e as c_int); - } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(errno: i32) -> String { - let mut buf = [0 as c_char; TMPBUF_SZ]; - extern "C" { - fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int; - } - - let p = buf.as_mut_ptr(); - unsafe { - if strerror_r(errno as c_int, p, buf.len()) < 0 { - panic!("strerror_r failure"); - } - let p = p as *const _; - str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned() - } -} - -pub fn getcwd() -> io::Result<PathBuf> { - let mut buf = Vec::with_capacity(512); - loop { - unsafe { - let ptr = buf.as_mut_ptr() as *mut libc::c_char; - if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() { - let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len(); - buf.set_len(len); - buf.shrink_to_fit(); - return Ok(PathBuf::from(OsString::from_vec(buf))); - } else { - let error = io::Error::last_os_error(); - if error.raw_os_error() != Some(libc::ERANGE) { - return Err(error); - } - } - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. - let cap = buf.capacity(); - buf.set_len(cap); - buf.reserve(1); - } - } -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - let p: &OsStr = p.as_ref(); - let p = CString::new(p.as_bytes())?; - unsafe { - match libc::chdir(p.as_ptr()) == (0 as c_int) { - true => Ok(()), - false => Err(io::Error::last_os_error()), - } - } -} - -pub struct SplitPaths<'a> { - iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>, fn(&'a [u8]) -> PathBuf>, -} - -pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> { - fn bytes_to_path(b: &[u8]) -> PathBuf { - PathBuf::from(<OsStr as OsStrExt>::from_bytes(b)) - } - fn is_colon(b: &u8) -> bool { - *b == b':' - } - let unparsed = unparsed.as_bytes(); - SplitPaths { - iter: unparsed - .split(is_colon as fn(&u8) -> bool) - .map(bytes_to_path as fn(&[u8]) -> PathBuf), - } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option<PathBuf> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError> -where - I: Iterator<Item = T>, - T: AsRef<OsStr>, -{ - let mut joined = Vec::new(); - let sep = b':'; - - for (i, path) in paths.enumerate() { - let path = path.as_ref().as_bytes(); - if i > 0 { - joined.push(sep) - } - if path.contains(&sep) { - return Err(JoinPathsError); - } - joined.extend_from_slice(path); - } - Ok(OsStringExt::from_vec(joined)) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "path segment contains separator `:`".fmt(f) - } -} - -impl StdError for JoinPathsError { - #[allow(deprecated)] - fn description(&self) -> &str { - "failed to join paths" - } -} - -pub fn current_exe() -> io::Result<PathBuf> { - #[cfg(test)] - use realstd::env; - - #[cfg(not(test))] - use crate::env; - - let exe_path = env::args().next().unwrap(); - let path = Path::new(&exe_path); - path.canonicalize() -} - -pub struct Env { - iter: vec::IntoIter<(OsString, OsString)>, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Iterator for Env { - type Item = (OsString, OsString); - fn next(&mut self) -> Option<(OsString, OsString)> { - self.iter.next() - } - fn size_hint(&self) -> (usize, Option<usize>) { - self.iter.size_hint() - } -} - -pub unsafe fn environ() -> *mut *const *const c_char { - extern "C" { - static mut environ: *const *const c_char; - } - &mut environ -} - -pub unsafe fn env_lock() -> StaticMutexGuard<'static> { - // It is UB to attempt to acquire this mutex reentrantly! - static ENV_LOCK: StaticMutex = StaticMutex::new(); - ENV_LOCK.lock() -} - -/// Returns a vector of (variable, value) byte-vector pairs for all the -/// environment variables of the current process. -pub fn env() -> Env { - unsafe { - let _guard = env_lock(); - let mut environ = *environ(); - if environ.is_null() { - panic!("os::env() failure getting env string from OS: {}", io::Error::last_os_error()); - } - let mut result = Vec::new(); - while !(*environ).is_null() { - if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) { - result.push(key_value); - } - environ = environ.add(1); - } - return Env { iter: result.into_iter(), _dont_send_or_sync_me: PhantomData }; - } - - fn parse(input: &[u8]) -> Option<(OsString, OsString)> { - // Strategy (copied from glibc): Variable name and value are separated - // by an ASCII equals sign '='. Since a variable name must not be - // empty, allow variable names starting with an equals sign. Skip all - // malformed lines. - if input.is_empty() { - return None; - } - let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1); - pos.map(|p| { - ( - OsStringExt::from_vec(input[..p].to_vec()), - OsStringExt::from_vec(input[p + 1..].to_vec()), - ) - }) - } -} - -pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - // environment variables with a nul byte can't be set, so their value is - // always None as well - let k = CString::new(k.as_bytes())?; - unsafe { - let _guard = env_lock(); - let s = libc::getenv(k.as_ptr()) as *const libc::c_char; - let ret = if s.is_null() { - None - } else { - Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) - }; - Ok(ret) - } -} - -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let k = CString::new(k.as_bytes())?; - let v = CString::new(v.as_bytes())?; - - unsafe { - let _guard = env_lock(); - cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop) - } -} - -pub fn unsetenv(n: &OsStr) -> io::Result<()> { - let nbuf = CString::new(n.as_bytes())?; - - unsafe { - let _guard = env_lock(); - cvt(libc::unsetenv(nbuf.as_ptr())).map(drop) - } -} - -pub fn page_size() -> usize { - unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize } -} - -pub fn temp_dir() -> PathBuf { - crate::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| PathBuf::from("/tmp")) -} - -pub fn home_dir() -> Option<PathBuf> { - crate::env::var_os("HOME").or_else(|| None).map(PathBuf::from) -} - -pub fn exit(code: i32) -> ! { - unsafe { libc::exit(code as c_int) } -} - -pub fn getpid() -> u32 { - unsafe { libc::getpid() as u32 } -} - -pub fn getppid() -> u32 { - unsafe { libc::getppid() as u32 } -} diff --git a/library/std/src/sys/vxworks/path.rs b/library/std/src/sys/vxworks/path.rs deleted file mode 100644 index 840a7ae0426..00000000000 --- a/library/std/src/sys/vxworks/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::ffi::OsStr; -use crate::path::Prefix; - -#[inline] -pub fn is_sep_byte(b: u8) -> bool { - b == b'/' -} - -#[inline] -pub fn is_verbatim_sep(b: u8) -> bool { - b == b'/' -} - -pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> { - None -} - -pub const MAIN_SEP_STR: &str = "/"; -pub const MAIN_SEP: char = '/'; diff --git a/library/std/src/sys/vxworks/pipe.rs b/library/std/src/sys/vxworks/pipe.rs deleted file mode 100644 index a18376212af..00000000000 --- a/library/std/src/sys/vxworks/pipe.rs +++ /dev/null @@ -1,107 +0,0 @@ -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::mem; -use crate::sync::atomic::AtomicBool; -use crate::sys::fd::FileDesc; -use crate::sys::{cvt, cvt_r}; -use libc::{self /*, c_int apparently not used? */}; - -pub struct AnonPipe(FileDesc); - -pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { - static INVALID: AtomicBool = AtomicBool::new(false); - - let mut fds = [0; 2]; - cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?; - - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - fd0.set_cloexec()?; - fd1.set_cloexec()?; - Ok((AnonPipe(fd0), AnonPipe(fd1))) -} - -impl AnonPipe { - pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - self.0.read(buf) - } - - pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - self.0.read_vectored(bufs) - } - - #[inline] - pub fn is_read_vectored(&self) -> bool { - self.0.is_read_vectored() - } - - pub fn write(&self, buf: &[u8]) -> io::Result<usize> { - self.0.write(buf) - } - - pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - self.0.write_vectored(bufs) - } - - #[inline] - pub fn is_write_vectored(&self) -> bool { - self.0.is_write_vectored() - } - - pub fn fd(&self) -> &FileDesc { - &self.0 - } - pub fn into_fd(self) -> FileDesc { - self.0 - } - pub fn diverge(&self) -> ! { - panic!() - } -} - -pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> { - // Set both pipes into nonblocking mode as we're gonna be reading from both - // in the `select` loop below, and we wouldn't want one to block the other! - let p1 = p1.into_fd(); - let p2 = p2.into_fd(); - p1.set_nonblocking_pipe(true)?; - p2.set_nonblocking_pipe(true)?; - - let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; - fds[0].fd = p1.raw(); - fds[0].events = libc::POLLIN; - fds[1].fd = p2.raw(); - fds[1].events = libc::POLLIN; - loop { - // wait for either pipe to become readable using `poll` - cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; - - if fds[0].revents != 0 && read(&p1, v1)? { - p2.set_nonblocking_pipe(false)?; - return p2.read_to_end(v2).map(drop); - } - if fds[1].revents != 0 && read(&p2, v2)? { - p1.set_nonblocking_pipe(false)?; - return p1.read_to_end(v1).map(drop); - } - } - - // Read as much as we can from each pipe, ignoring EWOULDBLOCK or - // EAGAIN. If we hit EOF, then this will happen because the underlying - // reader will return Ok(0), in which case we'll see `Ok` ourselves. In - // this case we flip the other fd back into blocking mode and read - // whatever's leftover on that file descriptor. - fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> { - match fd.read_to_end(dst) { - Ok(_) => Ok(true), - Err(e) => { - if e.raw_os_error() == Some(libc::EWOULDBLOCK) - || e.raw_os_error() == Some(libc::EAGAIN) - { - Ok(false) - } else { - Err(e) - } - } - } - } -} diff --git a/library/std/src/sys/vxworks/process/mod.rs b/library/std/src/sys/vxworks/process/mod.rs index c59782ff44b..dc6130eaa24 100644 --- a/library/std/src/sys/vxworks/process/mod.rs +++ b/library/std/src/sys/vxworks/process/mod.rs @@ -1,7 +1,9 @@ -pub use self::process_common::{Command, ExitCode, ExitStatus, Stdio, StdioPipes}; -pub use self::process_inner::Process; +pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; +pub use self::process_inner::{ExitStatus, Process}; pub use crate::ffi::OsString as EnvKey; +pub use crate::sys_common::process::CommandEnvs; +#[path = "../../unix/process/process_common.rs"] mod process_common; #[path = "process_vxworks.rs"] mod process_inner; diff --git a/library/std/src/sys/vxworks/process/process_common.rs b/library/std/src/sys/vxworks/process/process_common.rs deleted file mode 100644 index 6473a0c3cec..00000000000 --- a/library/std/src/sys/vxworks/process/process_common.rs +++ /dev/null @@ -1,399 +0,0 @@ -use crate::os::unix::prelude::*; - -use crate::collections::BTreeMap; -use crate::ffi::{CStr, CString, OsStr, OsString}; -use crate::fmt; -use crate::io; -use crate::ptr; -use crate::sys::fd::FileDesc; -use crate::sys::fs::{File, OpenOptions}; -use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::CommandEnv; - -use libc::{c_char, c_int, gid_t, uid_t, EXIT_FAILURE, EXIT_SUCCESS}; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - // Currently we try hard to ensure that the call to `.exec()` doesn't - // actually allocate any memory. While many platforms try to ensure that - // memory allocation works after a fork in a multithreaded process, it's - // been observed to be buggy and somewhat unreliable, so we do our best to - // just not do it at all! - // - // Along those lines, the `argv` and `envp` raw pointers here are exactly - // what's gonna get passed to `execvp`. The `argv` array starts with the - // `program` and ends with a NULL, and the `envp` pointer, if present, is - // also null-terminated. - // - // Right now we don't support removing arguments, so there's no much fancy - // support there, but we support adding and removing environment variables, - // so a side table is used to track where in the `envp` array each key is - // located. Whenever we add a key we update it in place if it's already - // present, and whenever we remove a key we update the locations of all - // other keys. - program: CString, - args: Vec<CString>, - argv: Argv, - env: CommandEnv, - - cwd: Option<CString>, - uid: Option<uid_t>, - gid: Option<gid_t>, - saw_nul: bool, - closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>, - stdin: Option<Stdio>, - stdout: Option<Stdio>, - stderr: Option<Stdio>, -} - -// Create a new type for `Argv`, so that we can make it `Send` and `Sync` -struct Argv(Vec<*const c_char>); - -// It is safe to make `Argv` `Send` and `Sync`, because it contains -// pointers to memory owned by `Command.args` -unsafe impl Send for Argv {} -unsafe impl Sync for Argv {} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option<AnonPipe>, - pub stdout: Option<AnonPipe>, - pub stderr: Option<AnonPipe>, -} - -// passed to do_exec() with configuration of what the child stdio should look -// like -pub struct ChildPipes { - pub stdin: ChildStdio, - pub stdout: ChildStdio, - pub stderr: ChildStdio, -} - -pub enum ChildStdio { - Inherit, - Explicit(c_int), - Owned(FileDesc), -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, - Fd(FileDesc), -} - -impl Command { - pub fn new(program: &OsStr) -> Command { - let mut saw_nul = false; - let program = os2c(program, &mut saw_nul); - Command { - argv: Argv(vec![program.as_ptr(), ptr::null()]), - args: vec![program.clone()], - program, - env: Default::default(), - cwd: None, - uid: None, - gid: None, - saw_nul, - closures: Vec::new(), - stdin: None, - stdout: None, - stderr: None, - } - } - - pub fn set_arg_0(&mut self, arg: &OsStr) { - // Set a new arg0 - let arg = os2c(arg, &mut self.saw_nul); - debug_assert!(self.argv.0.len() > 1); - self.argv.0[0] = arg.as_ptr(); - self.args[0] = arg; - } - - pub fn arg(&mut self, arg: &OsStr) { - // Overwrite the trailing NULL pointer in `argv` and then add a new null - // pointer. - let arg = os2c(arg, &mut self.saw_nul); - self.argv.0[self.args.len()] = arg.as_ptr(); - self.argv.0.push(ptr::null()); - - // Also make sure we keep track of the owned value to schedule a - // destructor for this memory. - self.args.push(arg); - } - - pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(os2c(dir, &mut self.saw_nul)); - } - pub fn uid(&mut self, id: uid_t) { - self.uid = Some(id); - } - pub fn gid(&mut self, id: gid_t) { - self.gid = Some(id); - } - - pub fn saw_nul(&self) -> bool { - self.saw_nul - } - pub fn get_argv(&self) -> &Vec<*const c_char> { - &self.argv.0 - } - - pub fn get_program(&self) -> &CStr { - &*self.program - } - - #[allow(dead_code)] - pub fn get_cwd(&self) -> &Option<CString> { - &self.cwd - } - #[allow(dead_code)] - pub fn get_uid(&self) -> Option<uid_t> { - self.uid - } - #[allow(dead_code)] - pub fn get_gid(&self) -> Option<gid_t> { - self.gid - } - - pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> { - &mut self.closures - } - - pub unsafe fn pre_exec(&mut self, _f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) { - // Fork() is not supported in vxWorks so no way to run the closure in the new procecss. - unimplemented!(); - } - - pub fn stdin(&mut self, stdin: Stdio) { - self.stdin = Some(stdin); - } - - pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = Some(stdout); - } - - pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = Some(stderr); - } - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn capture_env(&mut self) -> Option<CStringArray> { - let maybe_env = self.env.capture_if_changed(); - maybe_env.map(|env| construct_envp(env, &mut self.saw_nul)) - } - #[allow(dead_code)] - pub fn env_saw_path(&self) -> bool { - self.env.have_changed_path() - } - - pub fn setup_io( - &self, - default: Stdio, - needs_stdin: bool, - ) -> io::Result<(StdioPipes, ChildPipes)> { - let null = Stdio::Null; - let default_stdin = if needs_stdin { &default } else { &null }; - let stdin = self.stdin.as_ref().unwrap_or(default_stdin); - let stdout = self.stdout.as_ref().unwrap_or(&default); - let stderr = self.stderr.as_ref().unwrap_or(&default); - let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?; - let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?; - let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?; - let ours = StdioPipes { stdin: our_stdin, stdout: our_stdout, stderr: our_stderr }; - let theirs = ChildPipes { stdin: their_stdin, stdout: their_stdout, stderr: their_stderr }; - Ok((ours, theirs)) - } -} - -fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { - CString::new(s.as_bytes()).unwrap_or_else(|_e| { - *saw_nul = true; - CString::new("<string-with-nul>").unwrap() - }) -} - -// Helper type to manage ownership of the strings within a C-style array. -pub struct CStringArray { - items: Vec<CString>, - ptrs: Vec<*const c_char>, -} - -impl CStringArray { - pub fn with_capacity(capacity: usize) -> Self { - let mut result = CStringArray { - items: Vec::with_capacity(capacity), - ptrs: Vec::with_capacity(capacity + 1), - }; - result.ptrs.push(ptr::null()); - result - } - pub fn push(&mut self, item: CString) { - let l = self.ptrs.len(); - self.ptrs[l - 1] = item.as_ptr(); - self.ptrs.push(ptr::null()); - self.items.push(item); - } - pub fn as_ptr(&self) -> *const *const c_char { - self.ptrs.as_ptr() - } -} - -fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray { - let mut result = CStringArray::with_capacity(env.len()); - for (k, v) in env { - let mut k: OsString = k.into(); - - // Reserve additional space for '=' and null terminator - k.reserve_exact(v.len() + 2); - k.push("="); - k.push(&v); - - // Add the new entry into the array - if let Ok(item) = CString::new(k.into_vec()) { - result.push(item); - } else { - *saw_nul = true; - } - } - - result -} - -impl Stdio { - pub fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option<AnonPipe>)> { - match *self { - Stdio::Inherit => Ok((ChildStdio::Inherit, None)), - - // Make sure that the source descriptors are not an stdio - // descriptor, otherwise the order which we set the child's - // descriptors may blow away a descriptor which we are hoping to - // save. For example, suppose we want the child's stderr to be the - // parent's stdout, and the child's stdout to be the parent's - // stderr. No matter which we dup first, the second will get - // overwritten prematurely. - Stdio::Fd(ref fd) => { - if fd.raw() >= 0 && fd.raw() <= libc::STDERR_FILENO { - Ok((ChildStdio::Owned(fd.duplicate()?), None)) - } else { - Ok((ChildStdio::Explicit(fd.raw()), None)) - } - } - - Stdio::MakePipe => { - let (reader, writer) = pipe::anon_pipe()?; - let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) }; - Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours))) - } - - Stdio::Null => { - let mut opts = OpenOptions::new(); - opts.read(readable); - opts.write(!readable); - let path = unsafe { CStr::from_ptr("/null\0".as_ptr() as *const _) }; - let fd = File::open_c(&path, &opts)?; - Ok((ChildStdio::Owned(fd.into_fd()), None)) - } - } - } -} - -impl From<AnonPipe> for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - Stdio::Fd(pipe.into_fd()) - } -} - -impl From<File> for Stdio { - fn from(file: File) -> Stdio { - Stdio::Fd(file.into_fd()) - } -} - -impl ChildStdio { - pub fn fd(&self) -> Option<c_int> { - match *self { - ChildStdio::Inherit => None, - ChildStdio::Explicit(fd) => Some(fd), - ChildStdio::Owned(ref fd) => Some(fd.raw()), - } - } -} - -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.program != self.args[0] { - write!(f, "[{:?}] ", self.program)?; - } - write!(f, "{:?}", self.args[0])?; - - for arg in &self.args[1..] { - write!(f, " {:?}", arg)?; - } - Ok(()) - } -} - -/// Unix exit statuses -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(c_int); - -impl ExitStatus { - pub fn new(status: c_int) -> ExitStatus { - ExitStatus(status) - } - - fn exited(&self) -> bool { - libc::WIFEXITED(self.0) - } - - pub fn success(&self) -> bool { - self.code() == Some(0) - } - - pub fn code(&self) -> Option<i32> { - if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } - } - - pub fn signal(&self) -> Option<i32> { - if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } - } -} - -/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. -impl From<c_int> for ExitStatus { - fn from(a: c_int) -> ExitStatus { - ExitStatus(a) - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(code) = self.code() { - write!(f, "exit code: {}", code) - } else { - let signal = self.signal().unwrap(); - write!(f, "signal: {}", signal) - } - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(u8); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _); - pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _); - - #[inline] - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} diff --git a/library/std/src/sys/vxworks/process/process_vxworks.rs b/library/std/src/sys/vxworks/process/process_vxworks.rs index f7e84ae3de9..69adbcdddc9 100644 --- a/library/std/src/sys/vxworks/process/process_vxworks.rs +++ b/library/std/src/sys/vxworks/process/process_vxworks.rs @@ -1,3 +1,4 @@ +use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::sys; use crate::sys::cvt; @@ -67,7 +68,7 @@ impl Command { let _lock = sys::os::env_lock(); let ret = libc::rtpSpawn( - self.get_program().as_ptr(), + self.get_program_cstr().as_ptr(), self.get_argv().as_ptr() as *mut *const c_char, // argv c_envp as *mut *const c_char, 100 as c_int, // initial priority @@ -167,3 +168,47 @@ impl Process { } } } + +/// Unix exit statuses +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatus(c_int); + +impl ExitStatus { + pub fn new(status: c_int) -> ExitStatus { + ExitStatus(status) + } + + fn exited(&self) -> bool { + libc::WIFEXITED(self.0) + } + + pub fn success(&self) -> bool { + self.code() == Some(0) + } + + pub fn code(&self) -> Option<i32> { + if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } + } + + pub fn signal(&self) -> Option<i32> { + if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } + } +} + +/// Converts a raw `c_int` to a type-safe `ExitStatus` by wrapping it without copying. +impl From<c_int> for ExitStatus { + fn from(a: c_int) -> ExitStatus { + ExitStatus(a) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(code) = self.code() { + write!(f, "exit code: {}", code) + } else { + let signal = self.signal().unwrap(); + write!(f, "signal: {}", signal) + } + } +} diff --git a/library/std/src/sys/vxworks/rwlock.rs b/library/std/src/sys/vxworks/rwlock.rs deleted file mode 100644 index c90304c2b4a..00000000000 --- a/library/std/src/sys/vxworks/rwlock.rs +++ /dev/null @@ -1,114 +0,0 @@ -use crate::cell::UnsafeCell; -use crate::sync::atomic::{AtomicUsize, Ordering}; - -pub struct RWLock { - inner: UnsafeCell<libc::pthread_rwlock_t>, - write_locked: UnsafeCell<bool>, - num_readers: AtomicUsize, -} - -unsafe impl Send for RWLock {} -unsafe impl Sync for RWLock {} - -impl RWLock { - pub const fn new() -> RWLock { - RWLock { - inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER), - write_locked: UnsafeCell::new(false), - num_readers: AtomicUsize::new(0), - } - } - - #[inline] - pub unsafe fn read(&self) { - let r = libc::pthread_rwlock_rdlock(self.inner.get()); - if r == libc::EAGAIN { - panic!("rwlock maximum reader count exceeded"); - } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) { - if r == 0 { - self.raw_unlock(); - } - panic!("rwlock read lock would result in deadlock"); - } else { - debug_assert_eq!(r, 0); - self.num_readers.fetch_add(1, Ordering::Relaxed); - } - } - - #[inline] - pub unsafe fn try_read(&self) -> bool { - let r = libc::pthread_rwlock_tryrdlock(self.inner.get()); - if r == 0 { - if *self.write_locked.get() { - self.raw_unlock(); - false - } else { - self.num_readers.fetch_add(1, Ordering::Relaxed); - true - } - } else { - false - } - } - - #[inline] - pub unsafe fn write(&self) { - let r = libc::pthread_rwlock_wrlock(self.inner.get()); - // See comments above for why we check for EDEADLK and write_locked. We - // also need to check that num_readers is 0. - if r == libc::EDEADLK - || *self.write_locked.get() - || self.num_readers.load(Ordering::Relaxed) != 0 - { - if r == 0 { - self.raw_unlock(); - } - panic!("rwlock write lock would result in deadlock"); - } else { - debug_assert_eq!(r, 0); - } - *self.write_locked.get() = true; - } - - #[inline] - pub unsafe fn try_write(&self) -> bool { - let r = libc::pthread_rwlock_trywrlock(self.inner.get()); - if r == 0 { - if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 { - self.raw_unlock(); - false - } else { - *self.write_locked.get() = true; - true - } - } else { - false - } - } - - #[inline] - unsafe fn raw_unlock(&self) { - let r = libc::pthread_rwlock_unlock(self.inner.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - pub unsafe fn read_unlock(&self) { - debug_assert!(!*self.write_locked.get()); - self.num_readers.fetch_sub(1, Ordering::Relaxed); - self.raw_unlock(); - } - - #[inline] - pub unsafe fn write_unlock(&self) { - debug_assert_eq!(self.num_readers.load(Ordering::Relaxed), 0); - debug_assert!(*self.write_locked.get()); - *self.write_locked.get() = false; - self.raw_unlock(); - } - #[inline] - pub unsafe fn destroy(&self) { - let r = libc::pthread_rwlock_destroy(self.inner.get()); - debug_assert_eq!(r, 0); - } -} diff --git a/library/std/src/sys/vxworks/stack_overflow.rs b/library/std/src/sys/vxworks/stack_overflow.rs deleted file mode 100644 index 7b58c83193b..00000000000 --- a/library/std/src/sys/vxworks/stack_overflow.rs +++ /dev/null @@ -1,38 +0,0 @@ -#![cfg_attr(test, allow(dead_code))] - -use self::imp::{drop_handler, make_handler}; - -pub use self::imp::cleanup; -pub use self::imp::init; - -pub struct Handler { - _data: *mut libc::c_void, -} - -impl Handler { - pub unsafe fn new() -> Handler { - make_handler() - } -} - -impl Drop for Handler { - fn drop(&mut self) { - unsafe { - drop_handler(self); - } - } -} - -mod imp { - use crate::ptr; - - pub unsafe fn init() {} - - pub unsafe fn cleanup() {} - - pub unsafe fn make_handler() -> super::Handler { - super::Handler { _data: ptr::null_mut() } - } - - pub unsafe fn drop_handler(_handler: &mut super::Handler) {} -} diff --git a/library/std/src/sys/vxworks/stdio.rs b/library/std/src/sys/vxworks/stdio.rs deleted file mode 100644 index 92e9f205b4e..00000000000 --- a/library/std/src/sys/vxworks/stdio.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::io; -use crate::sys::fd::FileDesc; - -pub struct Stdin(()); -pub struct Stdout(()); -pub struct Stderr(()); - -impl Stdin { - pub const fn new() -> Stdin { - Stdin(()) - } -} - -impl io::Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { - let fd = FileDesc::new(libc::STDIN_FILENO); - let ret = fd.read(buf); - fd.into_raw(); // do not close this FD - ret - } -} - -impl Stdout { - pub const fn new() -> Stdout { - Stdout(()) - } -} - -impl io::Write for Stdout { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let fd = FileDesc::new(libc::STDOUT_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -impl Stderr { - pub const fn new() -> Stderr { - Stderr(()) - } -} - -impl io::Write for Stderr { - fn write(&mut self, buf: &[u8]) -> io::Result<usize> { - let fd = FileDesc::new(libc::STDERR_FILENO); - let ret = fd.write(buf); - fd.into_raw(); // do not close this FD - ret - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -pub fn is_ebadf(err: &io::Error) -> bool { - err.raw_os_error() == Some(libc::EBADF as i32) -} - -pub const STDIN_BUF_SIZE: usize = crate::sys_common::io::DEFAULT_BUF_SIZE; - -pub fn panic_output() -> Option<impl io::Write> { - Some(Stderr::new()) -} diff --git a/library/std/src/sys/vxworks/thread.rs b/library/std/src/sys/vxworks/thread.rs deleted file mode 100644 index 24a2e0f965d..00000000000 --- a/library/std/src/sys/vxworks/thread.rs +++ /dev/null @@ -1,155 +0,0 @@ -use crate::cmp; -use crate::ffi::CStr; -use crate::io; -use crate::mem; -use crate::ptr; -use crate::sys::{os, stack_overflow}; -use crate::time::Duration; - -pub const DEFAULT_MIN_STACK_SIZE: usize = 0x40000; // 256K - -pub struct Thread { - id: libc::pthread_t, -} - -// Some platforms may have pthread_t as a pointer in which case we still want -// a thread to be Send/Sync -unsafe impl Send for Thread {} -unsafe impl Sync for Thread {} - -// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc, -// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS. -unsafe fn pthread_attr_setstacksize( - attr: *mut libc::pthread_attr_t, - stack_size: libc::size_t, -) -> libc::c_int { - libc::pthread_attr_setstacksize(attr, stack_size) -} - -impl Thread { - // unsafe: see thread::Builder::spawn_unchecked for safety requirements - pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> { - let p = Box::into_raw(box p); - let mut native: libc::pthread_t = mem::zeroed(); - let mut attr: libc::pthread_attr_t = mem::zeroed(); - assert_eq!(libc::pthread_attr_init(&mut attr), 0); - - let stack_size = cmp::max(stack, min_stack_size(&attr)); - - match pthread_attr_setstacksize(&mut attr, stack_size) { - 0 => {} - n => { - assert_eq!(n, libc::EINVAL); - // EINVAL means |stack_size| is either too small or not a - // multiple of the system page size. Because it's definitely - // >= PTHREAD_STACK_MIN, it must be an alignment issue. - // Round up to the nearest page and try again. - let page_size = os::page_size(); - let stack_size = - (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); - } - }; - - let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); - // Note: if the thread creation fails and this assert fails, then p will - // be leaked. However, an alternative design could cause double-free - // which is clearly worse. - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); - - return if ret != 0 { - // The thread failed to start and as a result p was not consumed. Therefore, it is - // safe to reconstruct the box so that it gets deallocated. - drop(Box::from_raw(p)); - Err(io::Error::from_raw_os_error(ret)) - } else { - Ok(Thread { id: native }) - }; - - extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { - unsafe { - // Next, set up our stack overflow handler which may get triggered if we run - // out of stack. - let _handler = stack_overflow::Handler::new(); - // Finally, let's run some code. - Box::from_raw(main as *mut Box<dyn FnOnce()>)(); - } - ptr::null_mut() - } - } - - pub fn yield_now() { - let ret = unsafe { libc::sched_yield() }; - debug_assert_eq!(ret, 0); - } - - pub fn set_name(_name: &CStr) { - // VxWorks does not provide a way to set the task name except at creation time - } - - pub fn sleep(dur: Duration) { - let mut secs = dur.as_secs(); - let mut nsecs = dur.subsec_nanos() as _; - - // If we're awoken with a signal then the return value will be -1 and - // nanosleep will fill in `ts` with the remaining time. - unsafe { - while secs > 0 || nsecs > 0 { - let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, - tv_nsec: nsecs, - }; - secs -= ts.tv_sec as u64; - if libc::nanosleep(&ts, &mut ts) == -1 { - assert_eq!(os::errno(), libc::EINTR); - secs += ts.tv_sec as u64; - nsecs = ts.tv_nsec; - } else { - nsecs = 0; - } - } - } - } - - pub fn join(self) { - unsafe { - let ret = libc::pthread_join(self.id, ptr::null_mut()); - mem::forget(self); - assert!(ret == 0, "failed to join thread: {}", io::Error::from_raw_os_error(ret)); - } - } - - pub fn id(&self) -> libc::pthread_t { - self.id - } - - pub fn into_id(self) -> libc::pthread_t { - let id = self.id; - mem::forget(self); - id - } -} - -impl Drop for Thread { - fn drop(&mut self) { - let ret = unsafe { libc::pthread_detach(self.id) }; - debug_assert_eq!(ret, 0); - } -} - -#[cfg_attr(test, allow(dead_code))] -pub mod guard { - use crate::ops::Range; - pub type Guard = Range<usize>; - pub unsafe fn current() -> Option<Guard> { - None - } - pub unsafe fn init() -> Option<Guard> { - None - } - pub unsafe fn deinit() {} -} - -fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - libc::PTHREAD_STACK_MIN -} diff --git a/library/std/src/sys/vxworks/thread_local_key.rs b/library/std/src/sys/vxworks/thread_local_key.rs deleted file mode 100644 index 2c5b94b1e61..00000000000 --- a/library/std/src/sys/vxworks/thread_local_key.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![allow(dead_code)] // not used on all platforms - -use crate::mem; - -pub type Key = libc::pthread_key_t; - -#[inline] -pub unsafe fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key { - let mut key = 0; - assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); - key -} - -#[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - let r = libc::pthread_setspecific(key, value as *mut _); - debug_assert_eq!(r, 0); -} - -#[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - libc::pthread_getspecific(key) as *mut u8 -} - -#[inline] -pub unsafe fn destroy(key: Key) { - let r = libc::pthread_key_delete(key); - debug_assert_eq!(r, 0); -} - -#[inline] -pub fn requires_synchronized_create() -> bool { - false -} diff --git a/library/std/src/sys/vxworks/time.rs b/library/std/src/sys/vxworks/time.rs deleted file mode 100644 index 8f46f4d284f..00000000000 --- a/library/std/src/sys/vxworks/time.rs +++ /dev/null @@ -1,197 +0,0 @@ -use crate::cmp::Ordering; -use crate::time::Duration; -use core::hash::{Hash, Hasher}; - -pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; -use crate::convert::TryInto; - -const NSEC_PER_SEC: u64 = 1_000_000_000; - -#[derive(Copy, Clone)] -struct Timespec { - t: libc::timespec, -} - -impl Timespec { - const fn zero() -> Timespec { - Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } } - } - fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> { - if self >= other { - Ok(if self.t.tv_nsec >= other.t.tv_nsec { - Duration::new( - (self.t.tv_sec - other.t.tv_sec) as u64, - (self.t.tv_nsec - other.t.tv_nsec) as u32, - ) - } else { - Duration::new( - (self.t.tv_sec - 1 - other.t.tv_sec) as u64, - self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) - other.t.tv_nsec as u32, - ) - }) - } else { - match other.sub_timespec(self) { - Ok(d) => Err(d), - Err(d) => Ok(d), - } - } - } - - fn checked_add_duration(&self, other: &Duration) -> Option<Timespec> { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `libc::time_t` - .ok() - .and_then(|secs| self.t.tv_sec.checked_add(secs))?; - - // Nano calculations can't overflow because nanos are <1B which fit - // in a u32. - let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32; - if nsec >= NSEC_PER_SEC as u32 { - nsec -= NSEC_PER_SEC as u32; - secs = secs.checked_add(1)?; - } - Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } - - fn checked_sub_duration(&self, other: &Duration) -> Option<Timespec> { - let mut secs = other - .as_secs() - .try_into() // <- target type would be `libc::time_t` - .ok() - .and_then(|secs| self.t.tv_sec.checked_sub(secs))?; - - // Similar to above, nanos can't overflow. - let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32; - if nsec < 0 { - nsec += NSEC_PER_SEC as i32; - secs = secs.checked_sub(1)?; - } - Some(Timespec { t: libc::timespec { tv_sec: secs, tv_nsec: nsec as _ } }) - } -} - -impl PartialEq for Timespec { - fn eq(&self, other: &Timespec) -> bool { - self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec - } -} - -impl Eq for Timespec {} - -impl PartialOrd for Timespec { - fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> { - Some(self.cmp(other)) - } -} - -impl Ord for Timespec { - fn cmp(&self, other: &Timespec) -> Ordering { - let me = (self.t.tv_sec, self.t.tv_nsec); - let other = (other.t.tv_sec, other.t.tv_nsec); - me.cmp(&other) - } -} - -impl Hash for Timespec { - fn hash<H: Hasher>(&self, state: &mut H) { - self.t.tv_sec.hash(state); - self.t.tv_nsec.hash(state); - } -} -mod inner { - use crate::fmt; - use crate::sys::cvt; - use crate::time::Duration; - - use super::Timespec; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct Instant { - t: Timespec, - } - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] - pub struct SystemTime { - t: Timespec, - } - - pub const UNIX_EPOCH: SystemTime = - SystemTime { t: Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } } }; - - impl Instant { - pub fn now() -> Instant { - Instant { t: now(libc::CLOCK_MONOTONIC) } - } - - pub const fn zero() -> Instant { - Instant { t: Timespec::zero() } - } - - pub fn actually_monotonic() -> bool { - true - } - - pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> { - self.t.sub_timespec(&other.t).ok() - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> { - Some(Instant { t: self.t.checked_add_duration(other)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> { - Some(Instant { t: self.t.checked_sub_duration(other)? }) - } - } - - impl fmt::Debug for Instant { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Instant") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } - - impl SystemTime { - pub fn now() -> SystemTime { - SystemTime { t: now(libc::CLOCK_REALTIME) } - } - - pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> { - self.t.sub_timespec(&other.t) - } - - pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> { - Some(SystemTime { t: self.t.checked_add_duration(other)? }) - } - - pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> { - Some(SystemTime { t: self.t.checked_sub_duration(other)? }) - } - } - - impl From<libc::timespec> for SystemTime { - fn from(t: libc::timespec) -> SystemTime { - SystemTime { t: Timespec { t: t } } - } - } - - impl fmt::Debug for SystemTime { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SystemTime") - .field("tv_sec", &self.t.t.tv_sec) - .field("tv_nsec", &self.t.t.tv_nsec) - .finish() - } - } - - pub type clock_t = libc::c_int; - - fn now(clock: clock_t) -> Timespec { - let mut t = Timespec { t: libc::timespec { tv_sec: 0, tv_nsec: 0 } }; - cvt(unsafe { libc::clock_gettime(clock, &mut t.t) }).unwrap(); - t - } -} diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs index 661214e8f4c..81413f39dc1 100644 --- a/library/std/src/sys/wasi/ext/io.rs +++ b/library/std/src/sys/wasi/ext/io.rs @@ -160,3 +160,21 @@ impl AsRawFd for io::Stderr { sys::stdio::Stderr.as_raw_fd() } } + +impl<'a> AsRawFd for io::StdinLock<'a> { + fn as_raw_fd(&self) -> RawFd { + sys::stdio::Stdin.as_raw_fd() + } +} + +impl<'a> AsRawFd for io::StdoutLock<'a> { + fn as_raw_fd(&self) -> RawFd { + sys::stdio::Stdout.as_raw_fd() + } +} + +impl<'a> AsRawFd for io::StderrLock<'a> { + fn as_raw_fd(&self) -> RawFd { + sys::stdio::Stderr.as_raw_fd() + } +} diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index a7a4407ac38..a0a37ef8316 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -53,6 +53,7 @@ pub mod thread_local_key; pub mod time; #[path = "../unsupported/common.rs"] +#[deny(unsafe_op_in_unsafe_fn)] #[allow(unused)] mod common; pub use common::*; diff --git a/library/std/src/sys/wasm/futex_atomics.rs b/library/std/src/sys/wasm/futex_atomics.rs new file mode 100644 index 00000000000..3d8bf42f725 --- /dev/null +++ b/library/std/src/sys/wasm/futex_atomics.rs @@ -0,0 +1,17 @@ +use crate::arch::wasm32; +use crate::convert::TryInto; +use crate::sync::atomic::AtomicI32; +use crate::time::Duration; + +pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option<Duration>) { + let timeout = timeout.and_then(|t| t.as_nanos().try_into().ok()).unwrap_or(-1); + unsafe { + wasm32::memory_atomic_wait32(futex as *const AtomicI32 as *mut i32, expected, timeout); + } +} + +pub fn futex_wake(futex: &AtomicI32) { + unsafe { + wasm32::memory_atomic_notify(futex as *const AtomicI32 as *mut i32, 1); + } +} diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 2934ea59ab5..11c6896f050 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -55,6 +55,8 @@ cfg_if::cfg_if! { pub mod mutex; #[path = "rwlock_atomics.rs"] pub mod rwlock; + #[path = "futex_atomics.rs"] + pub mod futex; } else { #[path = "../unsupported/condvar.rs"] pub mod condvar; @@ -66,5 +68,6 @@ cfg_if::cfg_if! { } #[path = "../unsupported/common.rs"] +#[deny(unsafe_op_in_unsafe_fn)] mod common; pub use common::*; diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 559c4dc9c7c..657421e3fa4 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -47,7 +47,6 @@ pub type LPWCH = *mut WCHAR; pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; pub type LPWSADATA = *mut WSADATA; pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; -pub type LPSTR = *mut CHAR; pub type LPWSTR = *mut WCHAR; pub type LPFILETIME = *mut FILETIME; pub type LPWSABUF = *mut WSABUF; @@ -876,16 +875,6 @@ extern "system" { pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; - pub fn WideCharToMultiByte( - CodePage: UINT, - dwFlags: DWORD, - lpWideCharStr: LPCWSTR, - cchWideChar: c_int, - lpMultiByteStr: LPSTR, - cbMultiByte: c_int, - lpDefaultChar: LPCSTR, - lpUsedDefaultChar: LPBOOL, - ) -> c_int; pub fn closesocket(socket: SOCKET) -> c_int; pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int; diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 8178e6806b9..8c19cc78b09 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -4,7 +4,6 @@ use crate::ffi::{OsStr, OsString}; use crate::io::ErrorKind; use crate::os::windows::ffi::{OsStrExt, OsStringExt}; use crate::path::PathBuf; -use crate::ptr; use crate::time::Duration; pub use self::rand::hashmap_random_keys; @@ -206,58 +205,6 @@ fn os2path(s: &[u16]) -> PathBuf { PathBuf::from(OsString::from_wide(s)) } -#[allow(dead_code)] // Only used in backtrace::gnu::get_executable_filename() -fn wide_char_to_multi_byte( - code_page: u32, - flags: u32, - s: &[u16], - no_default_char: bool, -) -> crate::io::Result<Vec<i8>> { - unsafe { - let mut size = c::WideCharToMultiByte( - code_page, - flags, - s.as_ptr(), - s.len() as i32, - ptr::null_mut(), - 0, - ptr::null(), - ptr::null_mut(), - ); - if size == 0 { - return Err(crate::io::Error::last_os_error()); - } - - let mut buf = Vec::with_capacity(size as usize); - buf.set_len(size as usize); - - let mut used_default_char = c::FALSE; - size = c::WideCharToMultiByte( - code_page, - flags, - s.as_ptr(), - s.len() as i32, - buf.as_mut_ptr(), - buf.len() as i32, - ptr::null(), - if no_default_char { &mut used_default_char } else { ptr::null_mut() }, - ); - if size == 0 { - return Err(crate::io::Error::last_os_error()); - } - if no_default_char && used_default_char == c::TRUE { - return Err(crate::io::Error::new( - crate::io::ErrorKind::InvalidData, - "string cannot be converted to requested code page", - )); - } - - buf.set_len(size as usize); - - Ok(buf) - } -} - pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] { match unrolled_find_u16s(0, v) { // don't include the 0 diff --git a/library/std/src/sys/windows/time.rs b/library/std/src/sys/windows/time.rs index 900260169c7..91e4f765484 100644 --- a/library/std/src/sys/windows/time.rs +++ b/library/std/src/sys/windows/time.rs @@ -165,7 +165,7 @@ fn intervals2dur(intervals: u64) -> Duration { mod perf_counter { use super::NANOS_PER_SEC; - use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst}; + use crate::sync::atomic::{AtomicU64, Ordering}; use crate::sys::c; use crate::sys::cvt; use crate::sys_common::mul_div_u64; @@ -197,27 +197,25 @@ mod perf_counter { } fn frequency() -> c::LARGE_INTEGER { - static mut FREQUENCY: c::LARGE_INTEGER = 0; - static STATE: AtomicUsize = AtomicUsize::new(0); - + // Either the cached result of `QueryPerformanceFrequency` or `0` for + // uninitialized. Storing this as a single `AtomicU64` allows us to use + // `Relaxed` operations, as we are only interested in the effects on a + // single memory location. + static FREQUENCY: AtomicU64 = AtomicU64::new(0); + + let cached = FREQUENCY.load(Ordering::Relaxed); + // If a previous thread has filled in this global state, use that. + if cached != 0 { + return cached as c::LARGE_INTEGER; + } + // ... otherwise learn for ourselves ... + let mut frequency = 0; unsafe { - // If a previous thread has filled in this global state, use that. - if STATE.load(SeqCst) == 2 { - return FREQUENCY; - } - - // ... otherwise learn for ourselves ... - let mut frequency = 0; cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap(); - - // ... and attempt to be the one thread that stores it globally for - // all other threads - if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() { - FREQUENCY = frequency; - STATE.store(2, SeqCst); - } - frequency } + + FREQUENCY.store(frequency as u64, Ordering::Relaxed); + frequency } fn query() -> c::LARGE_INTEGER { diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index 1c5fbf7d701..a549770d8b3 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -8,27 +8,15 @@ use crate::io; use crate::io::prelude::*; use crate::path::{self, Path, PathBuf}; use crate::sync::atomic::{self, Ordering}; -use crate::sys::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; /// Max number of frames to print. const MAX_NB_FRAMES: usize = 100; -pub fn lock() -> impl Drop { - struct Guard; - static LOCK: Mutex = Mutex::new(); - - impl Drop for Guard { - fn drop(&mut self) { - unsafe { - LOCK.unlock(); - } - } - } - - unsafe { - LOCK.lock(); - Guard - } +// SAFETY: Don't attempt to lock this reentrantly. +pub unsafe fn lock() -> impl Drop { + static LOCK: StaticMutex = StaticMutex::new(); + LOCK.lock() } /// Prints the current backtrace. diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index a1e11d24465..f3e7efb955a 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -3,8 +3,7 @@ use crate::sys::mutex as imp; /// An OS-based mutual exclusion lock, meant for use in static variables. /// /// This mutex has a const constructor ([`StaticMutex::new`]), does not -/// implement `Drop` to cleanup resources, and causes UB when moved or used -/// reentrantly. +/// implement `Drop` to cleanup resources, and causes UB when used reentrantly. /// /// This mutex does not implement poisoning. /// @@ -16,12 +15,6 @@ unsafe impl Sync for StaticMutex {} impl StaticMutex { /// Creates a new mutex for use. - /// - /// Behavior is undefined if the mutex is moved after it is - /// first used with any of the functions below. - /// Also, the behavior is undefined if this mutex is ever used reentrantly, - /// i.e., `lock` is called by the thread currently holding the lock. - #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")] pub const fn new() -> Self { Self(imp::Mutex::new()) } @@ -29,19 +22,19 @@ impl StaticMutex { /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex /// will be unlocked. /// - /// It is undefined behaviour to call this function while locked, or if the - /// mutex has been moved since the last time this was called. + /// It is undefined behaviour to call this function while locked by the + /// same thread. #[inline] - pub unsafe fn lock(&self) -> StaticMutexGuard<'_> { + pub unsafe fn lock(&'static self) -> StaticMutexGuard { self.0.lock(); StaticMutexGuard(&self.0) } } #[must_use] -pub struct StaticMutexGuard<'a>(&'a imp::Mutex); +pub struct StaticMutexGuard(&'static imp::Mutex); -impl Drop for StaticMutexGuard<'_> { +impl Drop for StaticMutexGuard { #[inline] fn drop(&mut self) { unsafe { diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs index 23c17c8e2cf..5e75ac65de4 100644 --- a/library/std/src/sys_common/thread_parker/mod.rs +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -1,5 +1,9 @@ cfg_if::cfg_if! { - if #[cfg(any(target_os = "linux", target_os = "android"))] { + if #[cfg(any( + target_os = "linux", + target_os = "android", + all(target_arch = "wasm32", target_feature = "atomics"), + ))] { mod futex; pub use futex::Parker; } else { diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs index 9ebc991d638..41e7e6adcf1 100644 --- a/library/test/src/formatters/json.rs +++ b/library/test/src/formatters/json.rs @@ -182,8 +182,8 @@ impl<T: Write> OutputFormatter for JsonFormatter<T> { /// Base code taken form `libserialize::json::escape_str` struct EscapedString<S: AsRef<str>>(S); -impl<S: AsRef<str>> ::std::fmt::Display for EscapedString<S> { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { +impl<S: AsRef<str>> std::fmt::Display for EscapedString<S> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> ::std::fmt::Result { let mut start = 0; for (i, byte) in self.0.as_ref().bytes().enumerate() { diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 806df572cf9..ff1d82fc990 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -89,7 +89,7 @@ extern "C" { } cfg_if::cfg_if! { -if #[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm"))))] { +if #[cfg(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm")))] { // Not ARM EHABI #[repr(C)] #[derive(Copy, Clone, PartialEq)] diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index bc8bae14b21..84ed9446ae7 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -93,12 +93,12 @@ handled naturally. `./configure` should almost never be used for local installations, and is primarily useful for CI. Prefer to customize behavior using `config.toml`. -Finally, rustbuild makes use of the [gcc-rs crate] which has [its own +Finally, rustbuild makes use of the [cc-rs crate] which has [its own method][env-vars] of configuring C compilers and C flags via environment variables. -[gcc-rs crate]: https://github.com/alexcrichton/gcc-rs -[env-vars]: https://github.com/alexcrichton/gcc-rs#external-configuration-via-environment-variables +[cc-rs crate]: https://github.com/alexcrichton/cc-rs +[env-vars]: https://github.com/alexcrichton/cc-rs#external-configuration-via-environment-variables ## Build stages diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index d31f95ee5e9..07e582d4d29 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -7,13 +7,15 @@ use std::env; -use bootstrap::{Build, Config, Subcommand}; +use bootstrap::{Build, Config, Subcommand, VERSION}; fn main() { let args = env::args().skip(1).collect::<Vec<_>>(); let config = Config::parse(&args); - let changelog_suggestion = check_version(&config); + // check_version warnings are not printed during setup + let changelog_suggestion = + if matches!(config.cmd, Subcommand::Setup {..}) { None } else { check_version(&config) }; // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the // changelog warning, not the `x.py setup` message. @@ -40,8 +42,6 @@ fn main() { } fn check_version(config: &Config) -> Option<String> { - const VERSION: usize = 2; - let mut msg = String::new(); let suggestion = if let Some(seen) = config.changelog_seen { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 5c9184f4506..ce37adeb28c 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -447,7 +447,8 @@ class RustBuild(object): def downloading_llvm(self): opt = self.get_toml('download-ci-llvm', 'llvm') - return opt == "true" + return opt == "true" \ + or (opt == "if-available" and self.build == "x86_64-unknown-linux-gnu") def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None): if date is None: @@ -892,7 +893,7 @@ class RustBuild(object): submodules_names = [] for module in submodules: if module.endswith("llvm-project"): - if self.get_toml('llvm-config') or self.get_toml('download-ci-llvm') == 'true': + if self.get_toml('llvm-config') or self.downloading_llvm(): if self.get_toml('lld') != 'true': continue check = self.check_submodule(module, slow_submodules) @@ -1003,6 +1004,16 @@ def bootstrap(help_triggered): with open(toml_path) as config: build.config_toml = config.read() + profile = build.get_toml('profile') + if profile is not None: + include_file = 'config.{}.toml'.format(profile) + include_dir = os.path.join(build.rust_root, 'src', 'bootstrap', 'defaults') + include_path = os.path.join(include_dir, include_file) + # HACK: This works because `build.get_toml()` returns the first match it finds for a + # specific key, so appending our defaults at the end allows the user to override them + with open(include_path) as included_toml: + build.config_toml += os.linesep + included_toml.read() + config_verbose = build.get_toml('verbose', 'build') if config_verbose is not None: build.verbose = max(build.verbose, int(config_verbose)) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 4bc162abee6..707c1ff3efa 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -193,37 +193,37 @@ impl StepDescription { ); } - if paths.is_empty() { - for (desc, should_run) in v.iter().zip(should_runs) { + if paths.is_empty() || builder.config.include_default_paths { + for (desc, should_run) in v.iter().zip(&should_runs) { if desc.default && should_run.is_really_default { for pathset in &should_run.paths { desc.maybe_run(builder, pathset); } } } - } else { - for path in paths { - // strip CurDir prefix if present - let path = match path.strip_prefix(".") { - Ok(p) => p, - Err(_) => path, - }; + } - let mut attempted_run = false; - for (desc, should_run) in v.iter().zip(&should_runs) { - if let Some(suite) = should_run.is_suite_path(path) { - attempted_run = true; - desc.maybe_run(builder, suite); - } else if let Some(pathset) = should_run.pathset_for_path(path) { - attempted_run = true; - desc.maybe_run(builder, pathset); - } - } + for path in paths { + // strip CurDir prefix if present + let path = match path.strip_prefix(".") { + Ok(p) => p, + Err(_) => path, + }; - if !attempted_run { - panic!("error: no rules matched {}", path.display()); + let mut attempted_run = false; + for (desc, should_run) in v.iter().zip(&should_runs) { + if let Some(suite) = should_run.is_suite_path(path) { + attempted_run = true; + desc.maybe_run(builder, suite); + } else if let Some(pathset) = should_run.pathset_for_path(path) { + attempted_run = true; + desc.maybe_run(builder, pathset); } } + + if !attempted_run { + panic!("error: no rules matched {}", path.display()); + } } } } @@ -462,6 +462,7 @@ impl<'a> Builder<'a> { dist::LlvmTools, dist::RustDev, dist::Extended, + dist::BuildManifest, dist::HashSign ), Kind::Install => describe!( diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 40bf6c48296..5215ab3dd4f 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -234,14 +234,14 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car // Note that `libprofiler_builtins/build.rs` also computes this so if // you're changing something here please also change that. cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root); - " compiler-builtins-c".to_string() + " compiler-builtins-c" } else { - String::new() + "" }; if builder.no_std(target) == Some(true) { let mut features = "compiler-builtins-mem".to_string(); - features.push_str(&compiler_builtins_c_feature); + features.push_str(compiler_builtins_c_feature); // for no-std targets we only compile a few no_std crates cargo @@ -249,10 +249,10 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, stage: u32, car .arg("--manifest-path") .arg(builder.src.join("library/alloc/Cargo.toml")) .arg("--features") - .arg("compiler-builtins-mem compiler-builtins-c"); + .arg(features); } else { let mut features = builder.std_features(); - features.push_str(&compiler_builtins_c_feature); + features.push_str(compiler_builtins_c_feature); cargo .arg("--features") diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 6265bbaf5c2..3c1249f8de4 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -61,6 +61,7 @@ pub struct Config { pub profiler: bool, pub ignore_git: bool, pub exclude: Vec<PathBuf>, + pub include_default_paths: bool, pub rustc_error_format: Option<String>, pub json_output: bool, pub test_compare_mode: bool, @@ -390,7 +391,7 @@ struct Llvm { use_libcxx: Option<bool>, use_linker: Option<String>, allow_old_toolchain: Option<bool>, - download_ci_llvm: Option<bool>, + download_ci_llvm: Option<StringOrBool>, } #[derive(Deserialize, Default, Clone, Merge)] @@ -532,6 +533,7 @@ impl Config { let mut config = Config::default_opts(); config.exclude = flags.exclude; + config.include_default_paths = flags.include_default_paths; config.rustc_error_format = flags.rustc_error_format; config.json_output = flags.json_output; config.on_fail = flags.on_fail; @@ -733,7 +735,14 @@ impl Config { set(&mut config.llvm_use_libcxx, llvm.use_libcxx); config.llvm_use_linker = llvm.use_linker.clone(); config.llvm_allow_old_toolchain = llvm.allow_old_toolchain; - config.llvm_from_ci = llvm.download_ci_llvm.unwrap_or(false); + config.llvm_from_ci = match llvm.download_ci_llvm { + Some(StringOrBool::String(s)) => { + assert!(s == "if-available", "unknown option `{}` for download-ci-llvm", s); + config.build.triple == "x86_64-unknown-linux-gnu" + } + Some(StringOrBool::Bool(b)) => b, + None => false, + }; if config.llvm_from_ci { // None of the LLVM options, except assertions, are supported diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml index 4772de8a2cb..0ca928843d5 100644 --- a/src/bootstrap/defaults/config.compiler.toml +++ b/src/bootstrap/defaults/config.compiler.toml @@ -6,3 +6,8 @@ debug-logging = true # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true + +[llvm] +# Will download LLVM from CI if available on your platform (Linux only for now) +# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms +download-ci-llvm = "if-available" diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml index e4316f4d864..9874fdb767f 100644 --- a/src/bootstrap/defaults/config.library.toml +++ b/src/bootstrap/defaults/config.library.toml @@ -8,3 +8,8 @@ bench-stage = 0 [rust] # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. incremental = true + +[llvm] +# Will download LLVM from CI if available on your platform (Linux only for now) +# https://github.com/rust-lang/rust/issues/77084 tracks support for more platforms +download-ci-llvm = "if-available" diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index 3a0743da7a4..1887b805da1 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -2353,7 +2353,6 @@ impl Step for HashSign { cmd.arg(today.trim()); cmd.arg(addr); cmd.arg(&builder.config.channel); - cmd.arg(&builder.src); cmd.env("BUILD_MANIFEST_LEGACY", "1"); builder.create_dir(&distdir(builder)); @@ -2584,3 +2583,70 @@ impl Step for RustDev { Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) } } + +/// Tarball containing a prebuilt version of the build-manifest tool, intented to be used by the +/// release process to avoid cloning the monorepo and building stuff. +/// +/// Should not be considered stable by end users. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct BuildManifest { + pub target: TargetSelection, +} + +impl Step for BuildManifest { + type Output = PathBuf; + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/build-manifest") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(BuildManifest { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + let build_manifest = builder.tool_exe(Tool::BuildManifest); + + let name = pkgname(builder, "build-manifest"); + let tmp = tmpdir(builder); + + // Prepare the image. + let image = tmp.join("build-manifest-image"); + let image_bin = image.join("bin"); + let _ = fs::remove_dir_all(&image); + t!(fs::create_dir_all(&image_bin)); + builder.install(&build_manifest, &image_bin, 0o755); + + // Prepare the overlay. + let overlay = tmp.join("build-manifest-overlay"); + let _ = fs::remove_dir_all(&overlay); + builder.create_dir(&overlay); + builder.create(&overlay.join("version"), &builder.rust_version()); + for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] { + builder.install(&builder.src.join(file), &overlay, 0o644); + } + + // Create the final tarball. + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=build-manifest installed.") + .arg("--image-dir") + .arg(&image) + .arg("--work-dir") + .arg(&tmpdir(builder)) + .arg("--output-dir") + .arg(&distdir(builder)) + .arg("--non-installed-overlay") + .arg(&overlay) + .arg(format!("--package-name={}-{}", name, self.target.triple)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=build-manifest"); + + builder.run(&mut cmd); + distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple)) + } +} diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 319a0b4e611..22cfd0c5643 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -30,6 +30,7 @@ pub struct Flags { pub cmd: Subcommand, pub incremental: bool, pub exclude: Vec<PathBuf>, + pub include_default_paths: bool, pub rustc_error_format: Option<String>, pub json_output: bool, pub dry_run: bool, @@ -124,6 +125,7 @@ Subcommands: dist Build distribution artifacts install Install distribution artifacts run, r Run tools contained in this repository + setup Create a config.toml (making it easier to use `x.py` itself) To learn more about a subcommand, run `./x.py <subcommand> -h`", ); @@ -137,6 +139,11 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`", opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); opts.optmulti("", "exclude", "build paths to exclude", "PATH"); + opts.optflag( + "", + "include-default-paths", + "include default paths in addition to the provided ones", + ); opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optflag("", "dry-run", "dry run; don't build anything"); opts.optopt( @@ -466,15 +473,21 @@ Arguments: ); } "setup" => { - subcommand_help.push_str( + subcommand_help.push_str(&format!( "\n +x.py setup creates a `config.toml` which changes the defaults for x.py itself. + Arguments: This subcommand accepts a 'profile' to use for builds. For example: ./x.py setup library - The profile is optional and you will be prompted interactively if it is not given.", - ); + The profile is optional and you will be prompted interactively if it is not given. + The following profiles are available: + +{}", + Profile::all_for_help(" ").trim_end() + )); } _ => {} }; @@ -545,9 +558,7 @@ Arguments: profile_string.parse().unwrap_or_else(|err| { eprintln!("error: {}", err); eprintln!("help: the available profiles are:"); - for choice in Profile::all() { - eprintln!("- {}", choice); - } + eprint!("{}", Profile::all_for_help("- ")); std::process::exit(1); }) } else { @@ -618,6 +629,7 @@ Arguments: .into_iter() .map(|p| p.into()) .collect::<Vec<_>>(), + include_default_paths: matches.opt_present("include-default-paths"), deny_warnings: parse_deny_warnings(&matches), llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map( |s| s.parse::<bool>().expect("`llvm-skip-rebuild` should be either true or false"), diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index bf81c4bf28e..22a8e828862 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -177,8 +177,13 @@ const LLVM_TOOLS: &[&str] = &[ "llvm-size", // used to prints the size of the linker sections of a program "llvm-strip", // used to discard symbols from binary files to reduce their size "llvm-ar", // used for creating and modifying archive files + "llvm-dis", // used to disassemble LLVM bitcode + "llc", // used to compile LLVM bytecode + "opt", // used to optimize LLVM bytecode ]; +pub const VERSION: usize = 2; + /// A structure representing a Rust compiler. /// /// Each compiler has a `stage` that it is associated with and a `host` that diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 80c093e713e..7c64e5a0aad 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -77,7 +77,6 @@ impl Step for BuildManifest { cmd.arg(today.trim()); cmd.arg(addr); cmd.arg(&builder.config.channel); - cmd.arg(&builder.src); builder.create_dir(&distdir(builder)); builder.run(&mut cmd); diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs index dcfb9fd6734..a281061ace1 100644 --- a/src/bootstrap/setup.rs +++ b/src/bootstrap/setup.rs @@ -1,4 +1,5 @@ -use crate::t; +use crate::{t, VERSION}; +use std::fmt::Write as _; use std::path::{Path, PathBuf}; use std::str::FromStr; use std::{ @@ -20,7 +21,28 @@ impl Profile { } pub fn all() -> impl Iterator<Item = Self> { - [Profile::Compiler, Profile::Codegen, Profile::Library, Profile::User].iter().copied() + use Profile::*; + // N.B. these are ordered by how they are displayed, not alphabetically + [Library, Compiler, Codegen, User].iter().copied() + } + + pub fn purpose(&self) -> String { + use Profile::*; + match self { + Library => "Contribute to the standard library", + Compiler => "Contribute to the compiler or rustdoc", + Codegen => "Contribute to the compiler, and also modify LLVM or codegen", + User => "Install Rust from source", + } + .to_string() + } + + pub fn all_for_help(indent: &str) -> String { + let mut out = String::new(); + for choice in Profile::all() { + writeln!(&mut out, "{}{}: {}", indent, choice, choice.purpose()).unwrap(); + } + out } } @@ -29,10 +51,10 @@ impl FromStr for Profile { fn from_str(s: &str) -> Result<Self, Self::Err> { match s { - "a" | "lib" | "library" => Ok(Profile::Library), - "b" | "compiler" => Ok(Profile::Compiler), - "c" | "llvm" | "codegen" => Ok(Profile::Codegen), - "d" | "maintainer" | "user" => Ok(Profile::User), + "lib" | "library" => Ok(Profile::Library), + "compiler" | "rustdoc" => Ok(Profile::Compiler), + "llvm" | "codegen" => Ok(Profile::Codegen), + "maintainer" | "user" => Ok(Profile::User), _ => Err(format!("unknown profile: '{}'", s)), } } @@ -69,8 +91,9 @@ pub fn setup(src_path: &Path, profile: Profile) { let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml")); let settings = format!( "# Includes one of the default files in src/bootstrap/defaults\n\ - profile = \"{}\"\n", - profile + profile = \"{}\"\n\ + changelog-seen = {}\n", + profile, VERSION ); t!(fs::write(path, settings)); @@ -103,19 +126,37 @@ pub fn setup(src_path: &Path, profile: Profile) { // Used to get the path for `Subcommand::Setup` pub fn interactive_path() -> io::Result<Profile> { - let mut input = String::new(); - println!( - "Welcome to the Rust project! What do you want to do with x.py? -a) Contribute to the standard library -b) Contribute to the compiler -c) Contribute to the compiler, and also modify LLVM or codegen -d) Install Rust from source" - ); + fn abbrev_all() -> impl Iterator<Item = (String, Profile)> { + ('a'..).map(|c| c.to_string()).zip(Profile::all()) + } + + fn parse_with_abbrev(input: &str) -> Result<Profile, String> { + let input = input.trim().to_lowercase(); + for (letter, profile) in abbrev_all() { + if input == letter { + return Ok(profile); + } + } + input.parse() + } + + println!("Welcome to the Rust project! What do you want to do with x.py?"); + for (letter, profile) in abbrev_all() { + println!("{}) {}: {}", letter, profile, profile.purpose()); + } let template = loop { - print!("Please choose one (a/b/c/d): "); + print!( + "Please choose one ({}): ", + abbrev_all().map(|(l, _)| l).collect::<Vec<_>>().join("/") + ); io::stdout().flush()?; + let mut input = String::new(); io::stdin().read_line(&mut input)?; - break match input.trim().to_lowercase().parse() { + if input == "" { + eprintln!("EOF on stdin, when expecting answer to question. Giving up."); + std::process::exit(1); + } + break match parse_with_abbrev(&input) { Ok(profile) => profile, Err(err) => { println!("error: {}", err); diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 00522ee6b67..bda9e0f5784 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -966,6 +966,15 @@ impl Step for Compiletest { /// compiletest `mode` and `suite` arguments. For example `mode` can be /// "run-pass" or `suite` can be something like `debuginfo`. fn run(self, builder: &Builder<'_>) { + if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() { + eprintln!("\ +error: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail +help: use `--stage 1` instead +note: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `COMPILETEST_FORCE_STAGE0=1`." + ); + std::process::exit(1); + } + let compiler = self.compiler; let target = self.target; let mode = self.mode; diff --git a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile index 3c39a638496..f3f52ed61d1 100644 --- a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile @@ -84,9 +84,9 @@ RUN riscv64-linux-gnu-gcc addentropy.c -o rootfs/addentropy -static # download and build the riscv bootloader RUN git clone https://github.com/riscv/riscv-pk WORKDIR /tmp/riscv-pk -# nothing special about this revision: it is just master at the time of writing -# v1.0.0 doesn't build -RUN git checkout 5d9ed238e1cabfbca3c47f50d32894ce94bfc304 +# This revision fixes a fault in recent QEMU from 64-bit accesses to the PLIC +# commits later than this one should work too +RUN git checkout 7d8b7c0dab72108e3ea7bb7744d3f6cc907c7ef4 RUN mkdir build && cd build && \ ../configure --with-payload=/tmp/vmlinux --host=riscv64-linux-gnu && \ make -j$(nproc) && \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 58e2567a58f..14700aeea05 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -98,7 +98,9 @@ ENV RUST_CONFIGURE_ARGS \ --set llvm.thin-lto=true \ --set llvm.ninja=false \ --set rust.jemalloc -ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS \ + --include-default-paths \ + src/tools/build-manifest ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 101716d1601..01f15a82f0f 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -149,6 +149,10 @@ x--expand-yaml-anchors--remove: run: src/ci/scripts/install-sccache.sh <<: *step + - name: select Xcode + run: src/ci/scripts/select-xcode.sh + <<: *step + - name: install clang run: src/ci/scripts/install-clang.sh <<: *step @@ -457,6 +461,37 @@ jobs: NO_DEBUG_ASSERTIONS: 1 <<: *job-macos-xl + # This target only needs to support 11.0 and up as nothing else supports the hardware + - name: dist-aarch64-apple + env: + SCRIPT: ./x.py dist --stage 2 + RUST_CONFIGURE_ARGS: >- + --build=x86_64-apple-darwin + --host=aarch64-apple-darwin + --target=aarch64-apple-darwin + --enable-full-tools + --enable-sanitizers + --enable-profiler + --set rust.jemalloc + --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + SELECT_XCODE: /Applications/Xcode_12.2.app + USE_XCODE_CLANG: 1 + MACOSX_DEPLOYMENT_TARGET: 11.0 + MACOSX_STD_DEPLOYMENT_TARGET: 11.0 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + # Corresponds to 16K page size + # + # Shouldn't be needed if jemalloc-sys is updated to + # handle this platform like iOS or if we build on + # aarch64-apple-darwin itself. + # + # https://github.com/gnzlbg/jemallocator/blob/c27a859e98e3cb790dc269773d9da71a1e918458/jemalloc-sys/build.rs#L237 + JEMALLOC_SYS_WITH_LG_PAGE: 14 + <<: *job-macos-xl + ###################### # Windows Builders # ###################### @@ -565,7 +600,7 @@ jobs: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-msvc --host=x86_64-pc-windows-msvc - --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc + --target=x86_64-pc-windows-msvc --enable-full-tools --enable-profiler SCRIPT: python x.py dist @@ -584,6 +619,18 @@ jobs: DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-xl + - name: dist-aarch64-msvc + env: + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-msvc + --host=aarch64-pc-windows-msvc + --enable-full-tools + --enable-profiler + SCRIPT: python x.py dist + # RLS does not build for aarch64-pc-windows-msvc. See rust-lang/rls#1693 + DIST_REQUIRE_ALL_TOOLS: 0 + <<: *job-windows-xl + - name: dist-i686-mingw env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh index a1481f22f50..8070e90f155 100755 --- a/src/ci/scripts/install-clang.sh +++ b/src/ci/scripts/install-clang.sh @@ -12,10 +12,18 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" LLVM_VERSION="10.0.0" if isMacOS; then - curl -f "${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" | tar xJf - + # If the job selects a specific Xcode version, use that instead of + # downloading our own version. + if [[ ${USE_XCODE_CLANG-0} -eq 1 ]]; then + bindir="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/bin" + else + file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz" + curl -f "${file}" | tar xJf - + bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin" + fi - ciCommandSetEnv CC "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang" - ciCommandSetEnv CXX "$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin/clang++" + ciCommandSetEnv CC "${bindir}/clang" + ciCommandSetEnv CXX "${bindir}/clang++" # macOS 10.15 onwards doesn't have libraries in /usr/include anymore: those # are now located deep into the filesystem, under Xcode's own files. The diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index ae85d5cab01..1685fbbbbba 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -42,6 +42,13 @@ if isWindows; then arch=x86_64 mingw_archive="${MINGW_ARCHIVE_64}" ;; + *aarch64*) + # aarch64 is a cross-compiled target. Use the x86_64 + # mingw, since that's the host architecture. + bits=64 + arch=x86_64 + mingw_archive="${MINGW_ARCHIVE_64}" + ;; *) echo "src/ci/scripts/install-mingw.sh can't detect the builder's architecture" echo "please tweak it to recognize the builder named '${CI_JOB_NAME}'" diff --git a/src/ci/scripts/select-xcode.sh b/src/ci/scripts/select-xcode.sh new file mode 100755 index 00000000000..3b9c77d42ba --- /dev/null +++ b/src/ci/scripts/select-xcode.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# This script selects the Xcode instance to use. + +set -euo pipefail +IFS=$'\n\t' + +source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" + +if isMacOS; then + if [[ -s "${SELECT_XCODE-}" ]]; then + sudo xcode-select -s "${SELECT_XCODE}" + fi +fi diff --git a/src/doc/book b/src/doc/book -Subproject cb28dee95e5e50b793e6ba9291c5d1568d3ad72 +Subproject 451a1e30f2dd137aa04e142414eafb8d05f87f8 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject dd310616308e01f6cf227f46347b744aa56b77d +Subproject ca8169e69b479f615855d0eece7e318138fcfc0 diff --git a/src/doc/reference b/src/doc/reference -Subproject 56a13c082ee90736c08d6abdcd90462517b703d +Subproject 1b78182e71709169dc0f1c3acdc4541b6860e1c diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 7d3ff1c12db08a847a57a054be4a7951ce532d2 +Subproject 152475937a8d8a1f508d8eeb57db79139bc803d diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index bed10ca16d3..f6493e49c3c 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -497,8 +497,10 @@ point instructions in software. It takes one of the following values: This instructs `rustc` to generate code specifically for a particular processor. You can run `rustc --print target-cpus` to see the valid options to pass -here. Additionally, `native` can be passed to use the processor of the host -machine. Each target has a default base CPU. +here. Each target has a default base CPU. Special values include: + +* `native` can be passed to use the processor of the host machine. +* `generic` refers to an LLVM target with minimal features but modern tuning. ## target-feature @@ -530,6 +532,20 @@ This also supports the feature `+crt-static` and `-crt-static` to control Each target and [`target-cpu`](#target-cpu) has a default set of enabled features. +## tune-cpu + +This instructs `rustc` to schedule code specifically for a particular +processor. This does not affect the compatibility (instruction sets or ABI), +but should make your code slightly more efficient on the selected CPU. + +The valid options are the same as those for [`target-cpu`](#target-cpu). +The default is `None`, which LLVM translates as the `target-cpu`. + +This is an unstable option. Use `-Z tune-cpu=machine` to specify a value. + +Due to limitations in LLVM (12.0.0-git9218f92), this option is currently +effective only for x86 targets. + [option-emit]: ../command-line-arguments.md#option-emit [option-o-optimize]: ../command-line-arguments.md#option-o-optimize [profile-guided optimization]: ../profile-guided-optimization.md diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 6c605f045e5..ae55297b78c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -37,7 +37,7 @@ target | std | host | notes `i686-pc-windows-gnu` | ✓ | ✓ | 32-bit MinGW (Windows 7+) `i686-pc-windows-msvc` | ✓ | ✓ | 32-bit MSVC (Windows 7+) `i686-unknown-linux-gnu` | ✓ | ✓ | 32-bit Linux (kernel 2.6.32+, glibc 2.11+) -`x86_64-apple-darwin` | ✓ | ✓ | 64-bit OSX (10.7+, Lion+) +`x86_64-apple-darwin` | ✓ | ✓ | 64-bit macOS (10.7+, Lion+) `x86_64-pc-windows-gnu` | ✓ | ✓ | 64-bit MinGW (Windows 7+) `x86_64-pc-windows-msvc` | ✓ | ✓ | 64-bit MSVC (Windows 7+) `x86_64-unknown-linux-gnu` | ✓ | ✓ | 64-bit Linux (kernel 2.6.32+, glibc 2.11+) @@ -57,10 +57,11 @@ Specifically, these platforms are required to have each of the following: target | std | host | notes -------|-----|------|------- +`aarch64-apple-darwin` | ✓ | ✓ | ARM64 macOS (11.0+, Big Sur+) `aarch64-apple-ios` | ✓ | | ARM64 iOS `aarch64-fuchsia` | ✓ | | ARM64 Fuchsia `aarch64-linux-android` | ✓ | | ARM64 Android -`aarch64-pc-windows-msvc` | ✓ | | ARM64 Windows MSVC +`aarch64-pc-windows-msvc` | ✓ | ✓ | ARM64 Windows MSVC `aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17) `aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL `aarch64-unknown-none` | * | | Bare ARM64, hardfloat @@ -145,7 +146,6 @@ not available. target | std | host | notes -------|-----|------|------- -`aarch64-apple-darwin` | ? | | ARM64 macOS `aarch64-apple-tvos` | * | | ARM64 tvOS `aarch64-unknown-cloudabi` | ✓ | | ARM64 CloudABI `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD @@ -168,7 +168,7 @@ target | std | host | notes `avr-unknown-gnu-atmega328` | ✗ | | AVR. Requires `-Z build-std=core` `hexagon-unknown-linux-musl` | ? | | `i386-apple-ios` | ✓ | | 32-bit x86 iOS -`i686-apple-darwin` | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) +`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+) `i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support `i686-unknown-cloudabi` | ✓ | | 32-bit CloudABI `i686-unknown-uefi` | ? | | 32-bit UEFI diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md index 93454b4f909..a3fa525be1d 100644 --- a/src/doc/rustdoc/src/SUMMARY.md +++ b/src/doc/rustdoc/src/SUMMARY.md @@ -8,5 +8,5 @@ - [Linking to items by name](linking-to-items-by-name.md) - [Lints](lints.md) - [Passes](passes.md) -- [Advanced Features](advanced-features.md) +- [Advanced features](advanced-features.md) - [Unstable features](unstable-features.md) diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 8be9489c617..5128ff13b7a 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -1,4 +1,4 @@ -# Advanced Features +# Advanced features The features listed on this page fall outside the rest of the main categories. diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md index 5e46ef583f6..76e04398530 100644 --- a/src/doc/rustdoc/src/linking-to-items-by-name.md +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -1,6 +1,7 @@ # Linking to items by name -Rustdoc is capable of directly linking to other rustdoc pages in Markdown documentation using the path of item as a link. +Rustdoc is capable of directly linking to other rustdoc pages using the path of +the item as a link. For example, in the following code all of the links will link to the rustdoc page for `Bar`: @@ -19,15 +20,26 @@ pub struct Foo3; /// This struct is also not [`Bar`] pub struct Foo4; +/// This struct *is* [`Bar`]! pub struct Bar; ``` -You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. Backticks around the link will be stripped. +Backticks around the link will be stripped, so ``[`Option`]`` will correctly +link to `Option`. + +You can refer to anything in scope, and use paths, including `Self`, `self`, +`super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros, respectively. + +You can also refer to items with generic parameters like `Vec<T>`. The link will +resolve as if you had written ``[`Vec<T>`](Vec)``. Fully-qualified syntax (for example, +`<Vec as IntoIterator>::into_iter()`) is [not yet supported][fqs-issue], however. + +[fqs-issue]: https://github.com/rust-lang/rust/issues/74563 ```rust,edition2018 use std::sync::mpsc::Receiver; -/// This is an version of [`Receiver`], with support for [`std::future`]. +/// This is a version of [`Receiver<T>`] with support for [`std::future`]. /// /// You can obtain a [`std::future::Future`] by calling [`Self::recv()`]. pub struct AsyncReceiver<T> { @@ -44,13 +56,15 @@ impl<T> AsyncReceiver<T> { You can also link to sections using URL fragment specifiers: ```rust -/// This is a special implementation of [positional parameters] +/// This is a special implementation of [positional parameters]. /// /// [positional parameters]: std::fmt#formatting-parameters struct MySpecialFormatter; ``` -Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: +Paths in Rust have three namespaces: type, value, and macro. Item names must be +unique within their namespace, but can overlap with items outside of their +namespace. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `fn@`, `function@`, `mod@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: ```rust /// See also: [`Foo`](struct@Foo) @@ -62,4 +76,19 @@ struct Foo {} fn Foo() {} ``` -Note: Because of how `macro_rules` macros are scoped in Rust, the intra-doc links of a `macro_rules` macro will be resolved relative to the crate root, as opposed to the module it is defined in. +You can also disambiguate for functions by adding `()` after the function name, +or for macros by adding `!` after the macro name: + +```rust +/// See also: [`Foo`](struct@Foo) +struct Bar; + +/// This is different from [`Foo()`] +struct Foo {} + +fn Foo() {} +``` + +Note: Because of how `macro_rules!` macros are scoped in Rust, the intra-doc links of a `macro_rules!` macro will be resolved [relative to the crate root][#72243], as opposed to the module it is defined in. + +[#72243]: https://github.com/rust-lang/rust/issues/72243 diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index d8c0bab2259..cb9099cd50b 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -4,18 +4,18 @@ can use them like any other lints by doing this: ```rust,ignore -#![allow(missing_docs)] // allowing the lint, no message -#![warn(missing_docs)] // warn if there is missing docs -#![deny(missing_docs)] // rustdoc will fail if there is missing docs +#![allow(missing_docs)] // allows the lint, no diagnostics will be reported +#![warn(missing_docs)] // warn if there are missing docs +#![deny(missing_docs)] // error if there are missing docs ``` Here is the list of the lints provided by `rustdoc`: ## broken_intra_doc_links -This lint **warns by default**. This lint detects when an [intra-doc link] fails to get resolved. For example: +This lint **warns by default**. This lint detects when an [intra-doc link] fails to be resolved. For example: - [intra-doc link]: linking-to-items-by-name.html +[intra-doc link]: linking-to-items-by-name.md ```rust /// I want to link to [`Nonexistent`] but it doesn't exist! diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-backend.md b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md new file mode 100644 index 00000000000..878c894a6ca --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md @@ -0,0 +1,31 @@ +# `codegen-backend` + +The tracking issue for this feature is: [#77933](https://github.com/rust-lang/rust/issues/77933). + +------------------------ + +This feature allows you to specify a path to a dynamic library to use as rustc's +code generation backend at runtime. + +Set the `-Zcodegen-backend=<path>` compiler flag to specify the location of the +backend. The library must be of crate type `dylib` and must contain a function +named `__rustc_codegen_backend` with a signature of `fn() -> Box<dyn rustc_codegen_ssa::traits::CodegenBackend>`. + +## Example +See also the [`hotplug_codegen_backend`](https://github.com/rust-lang/rust/tree/master/src/test/run-make-fulldeps/hotplug_codegen_backend) test +for a full example. + +```rust,ignore +use rustc_codegen_ssa::traits::CodegenBackend; + +struct MyBackend; + +impl CodegenBackend for MyBackend { + // Implement codegen methods +} + +#[no_mangle] +pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> { + Box::new(MyBackend) +} +``` diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index af39424ec6c..6e4e1f78b96 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -27,7 +27,7 @@ Inline assembly is currently supported on the following architectures: - RISC-V - NVPTX - Hexagon -- MIPS32 +- MIPS32r2 and MIPS64r2 ## Basic usage @@ -513,8 +513,8 @@ Here is the list of currently supported register classes: | ARM | `qreg` | `q[0-15]` | `w` | | ARM | `qreg_low8` | `q[0-7]` | `t` | | ARM | `qreg_low4` | `q[0-3]` | `x` | -| MIPS32 | `reg` | `$[2-25]` | `r` | -| MIPS32 | `freg` | `$f[0-31]` | `f` | +| MIPS | `reg` | `$[2-25]` | `r` | +| MIPS | `freg` | `$f[0-31]` | `f` | | NVPTX | `reg16` | None\* | `h` | | NVPTX | `reg32` | None\* | `r` | | NVPTX | `reg64` | None\* | `l` | @@ -551,7 +551,9 @@ Each register class has constraints on which value types they can be used with. | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` | | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` | | MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | -| MIPS32 | `freg` | None | `f32` | +| MIPS32 | `freg` | None | `f32`, `f64` | +| MIPS64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` | +| MIPS64 | `freg` | None | `f32`, `f64` | | NVPTX | `reg16` | None | `i8`, `i16` | | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | @@ -600,7 +602,6 @@ Some registers have multiple names. These are all treated by the compiler as ide | ARM | `r13` | `sp` | | ARM | `r14` | `lr` | | ARM | `r15` | `pc` | -| MIPS32 | `$[2-25]` | Please [see the Wikipedia page][mips-regs] | | RISC-V | `x0` | `zero` | | RISC-V | `x1` | `ra` | | RISC-V | `x2` | `sp` | @@ -621,8 +622,6 @@ Some registers have multiple names. These are all treated by the compiler as ide | Hexagon | `r30` | `fr` | | Hexagon | `r31` | `lr` | -[mips-regs]: https://en.wikibooks.org/wiki/MIPS_Assembly/Register_File#Registers - Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | @@ -637,11 +636,11 @@ Some registers cannot be used for input or output operands: | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). | | AArch64 | `xzr` | This is a constant zero register which can't be modified. | | ARM | `pc` | This is the program counter, not a real register. | -| MIPS32 | `$0` or `$zero` | This is a constant zero register which can't be modified. | -| MIPS32 | `$1` or `$at` | Reserved for assembler. | -| MIPS32 | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | -| MIPS32 | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | -| MIPS32 | `$ra` | Return address cannot be used as inputs or outputs. | +| MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | +| MIPS | `$1` or `$at` | Reserved for assembler. | +| MIPS | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | +| MIPS | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | +| MIPS | `$ra` | Return address cannot be used as inputs or outputs. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | @@ -689,8 +688,8 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | ARM | `dreg` | None | `d0` | `P` | | ARM | `qreg` | None | `q0` | `q` | | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` | -| MIPS32 | `reg` | None | `$2` | None | -| MIPS32 | `freg` | None | `$f0` | None | +| MIPS | `reg` | None | `$2` | None | +| MIPS | `freg` | None | `$f0` | None | | NVPTX | `reg16` | None | `rs0` | None | | NVPTX | `reg32` | None | `r0` | None | | NVPTX | `reg64` | None | `rd0` | None | diff --git a/src/doc/unstable-book/src/library-features/default-free-fn.md b/src/doc/unstable-book/src/library-features/default-free-fn.md index 5dff73a94dd..d40a27dddf3 100644 --- a/src/doc/unstable-book/src/library-features/default-free-fn.md +++ b/src/doc/unstable-book/src/library-features/default-free-fn.md @@ -10,6 +10,8 @@ Adds a free `default()` function to the `std::default` module. This function just forwards to [`Default::default()`], but may remove repetition of the word "default" from the call site. +[`Default::default()`]: https://doc.rust-lang.org/nightly/std/default/trait.Default.html#tymethod.default + Here is an example: ```rust diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index bae51e6f9ee..b2d343fd7af 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -207,30 +207,46 @@ class StdRefCellProvider: yield "borrow", self.borrow -# Yield each key (and optionally value) from a BoxedNode. -def children_of_node(boxed_node, height, want_values): +# Yields children (in a provider's sense of the word) for a tree headed by a BoxedNode. +# In particular, yields each key/value pair in the node and in any child nodes. +def children_of_node(boxed_node, height): def cast_to_internal(node): - internal_type_name = str(node.type.target()).replace("LeafNode", "InternalNode", 1) + internal_type_name = node.type.target().name.replace("LeafNode", "InternalNode", 1) internal_type = lookup_type(internal_type_name) return node.cast(internal_type.pointer()) node_ptr = unwrap_unique_or_non_null(boxed_node["ptr"]) - node_ptr = cast_to_internal(node_ptr) if height > 0 else node_ptr - leaf = node_ptr["data"] if height > 0 else node_ptr.dereference() + leaf = node_ptr.dereference() keys = leaf["keys"] - values = leaf["vals"] + vals = leaf["vals"] + edges = cast_to_internal(node_ptr)["edges"] if height > 0 else None length = int(leaf["len"]) for i in xrange(0, length + 1): if height > 0: - child_ptr = node_ptr["edges"][i]["value"]["value"] - for child in children_of_node(child_ptr, height - 1, want_values): + boxed_child_node = edges[i]["value"]["value"] + for child in children_of_node(boxed_child_node, height - 1): yield child if i < length: - if want_values: - yield keys[i]["value"]["value"], values[i]["value"]["value"] - else: - yield keys[i]["value"]["value"] + # Avoid "Cannot perform pointer math on incomplete type" on zero-sized arrays. + key = keys[i]["value"]["value"] if keys.type.sizeof > 0 else None + val = vals[i]["value"]["value"] if vals.type.sizeof > 0 else None + yield key, val + + +# Yields children for a BTreeMap. +def children_of_map(map): + if map["length"] > 0: + root = map["root"] + if root.type.name.startswith("core::option::Option<"): + root = root.cast(gdb.lookup_type(root.type.name[21:-1])) + boxed_root_node = root["node"] + height = root["height"] + for i, (key, val) in enumerate(children_of_node(boxed_root_node, height)): + if key is not None: + yield "key{}".format(i), key + if val is not None: + yield "val{}".format(i), val class StdBTreeSetProvider: @@ -242,15 +258,8 @@ class StdBTreeSetProvider: def children(self): inner_map = self.valobj["map"] - if inner_map["length"] > 0: - root = inner_map["root"] - if "core::option::Option<" in root.type.name: - type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1] - root = root.cast(gdb.lookup_type(type_name)) - - node_ptr = root["node"] - for i, child in enumerate(children_of_node(node_ptr, root["height"], False)): - yield "[{}]".format(i), child + for child in children_of_map(inner_map): + yield child @staticmethod def display_hint(): @@ -265,16 +274,8 @@ class StdBTreeMapProvider: return "BTreeMap(size={})".format(self.valobj["length"]) def children(self): - if self.valobj["length"] > 0: - root = self.valobj["root"] - if "core::option::Option<" in root.type.name: - type_name = str(root.type.name).replace("core::option::Option<", "", 1)[:-1] - root = root.cast(gdb.lookup_type(type_name)) - - node_ptr = root["node"] - for i, child in enumerate(children_of_node(node_ptr, root["height"], True)): - yield "key{}".format(i), child[0] - yield "val{}".format(i), child[1] + for child in children_of_map(self.valobj): + yield child @staticmethod def display_hint(): diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index c039b181178..b659f3eab43 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -201,6 +201,37 @@ impl Cfg { _ => false, } } + + /// Attempt to simplify this cfg by assuming that `assume` is already known to be true, will + /// return `None` if simplification managed to completely eliminate any requirements from this + /// `Cfg`. + /// + /// See `tests::test_simplify_with` for examples. + pub(crate) fn simplify_with(&self, assume: &Cfg) -> Option<Cfg> { + if self == assume { + return None; + } + + if let Cfg::All(a) = self { + let mut sub_cfgs: Vec<Cfg> = if let Cfg::All(b) = assume { + a.iter().filter(|a| !b.contains(a)).cloned().collect() + } else { + a.iter().filter(|&a| a != assume).cloned().collect() + }; + let len = sub_cfgs.len(); + return match len { + 0 => None, + 1 => sub_cfgs.pop(), + _ => Some(Cfg::All(sub_cfgs)), + }; + } else if let Cfg::All(b) = assume { + if b.contains(self) { + return None; + } + } + + Some(self.clone()) + } } impl ops::Not for Cfg { diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 794a7bcaf1c..3a78269f19a 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -433,3 +433,39 @@ fn test_render_long_html() { ); }) } + +#[test] +fn test_simplify_with() { + // This is a tiny subset of things that could be simplified, but it likely covers 90% of + // real world usecases well. + with_default_session_globals(|| { + let foo = word_cfg("foo"); + let bar = word_cfg("bar"); + let baz = word_cfg("baz"); + let quux = word_cfg("quux"); + + let foobar = Cfg::All(vec![foo.clone(), bar.clone()]); + let barbaz = Cfg::All(vec![bar.clone(), baz.clone()]); + let foobarbaz = Cfg::All(vec![foo.clone(), bar.clone(), baz.clone()]); + let bazquux = Cfg::All(vec![baz.clone(), quux.clone()]); + + // Unrelated cfgs don't affect each other + assert_eq!(foo.simplify_with(&bar).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&bazquux).as_ref(), Some(&foobar)); + + // Identical cfgs are eliminated + assert_eq!(foo.simplify_with(&foo), None); + assert_eq!(foobar.simplify_with(&foobar), None); + + // Multiple cfgs eliminate a single assumed cfg + assert_eq!(foobar.simplify_with(&foo).as_ref(), Some(&bar)); + assert_eq!(foobar.simplify_with(&bar).as_ref(), Some(&foo)); + + // A single cfg is eliminated by multiple assumed cfg containing it + assert_eq!(foo.simplify_with(&foobar), None); + + // Multiple cfgs eliminate the matching subset of multiple assumed cfg + assert_eq!(foobar.simplify_with(&barbaz).as_ref(), Some(&foo)); + assert_eq!(foobar.simplify_with(&foobarbaz), None); + }); +} diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 79ff7fc62d5..6267b02e5d2 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -130,7 +130,7 @@ pub fn try_inline( attrs, inner, visibility: clean::Public, - stability: cx.tcx.lookup_stability(did).clean(cx), + stability: cx.tcx.lookup_stability(did).cloned(), deprecation: cx.tcx.lookup_deprecation(did).clean(cx), def_id: did, }); @@ -461,7 +461,7 @@ pub fn build_impl( name: None, attrs, visibility: clean::Inherited, - stability: tcx.lookup_stability(did).clean(cx), + stability: tcx.lookup_stability(did).cloned(), deprecation: tcx.lookup_deprecation(did).clean(cx), def_id: did, }); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 501891da573..776b131a076 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -19,7 +19,6 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_infer::infer::region_constraints::{Constraint, RegionConstraintData}; use rustc_middle::bug; use rustc_middle::middle::resolve_lifetime as rl; -use rustc_middle::middle::stability; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{InternalSubsts, Subst}; use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; @@ -274,7 +273,7 @@ impl Clean<Item> for doctree::Module<'_> { attrs, source: span.clean(cx), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), inner: ModuleItem(Module { is_crate: self.is_crate, items }), @@ -914,7 +913,7 @@ impl Clean<Item> for doctree::Function<'_> { attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), def_id: did.to_def_id(), inner: FunctionItem(Function { @@ -1023,7 +1022,7 @@ impl Clean<Item> for doctree::Trait<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: TraitItem(Trait { auto: self.is_auto.clean(cx), @@ -1047,7 +1046,7 @@ impl Clean<Item> for doctree::TraitAlias<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: TraitAliasItem(TraitAlias { generics: self.generics.clean(cx), @@ -1832,7 +1831,7 @@ impl Clean<Item> for doctree::Struct<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: StructItem(Struct { struct_type: self.struct_type, @@ -1852,7 +1851,7 @@ impl Clean<Item> for doctree::Union<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: UnionItem(Union { struct_type: self.struct_type, @@ -1882,7 +1881,7 @@ impl Clean<Item> for doctree::Enum<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: EnumItem(Enum { variants: self.variants.iter().map(|v| v.clean(cx)).collect(), @@ -1900,7 +1899,7 @@ impl Clean<Item> for doctree::Variant<'_> { attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: Inherited, - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), inner: VariantItem(Variant { kind: self.def.clean(cx) }), @@ -2049,7 +2048,7 @@ impl Clean<Item> for doctree::Typedef<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: TypedefItem(Typedef { type_, generics: self.gen.clean(cx), item_type }, false), } @@ -2064,7 +2063,7 @@ impl Clean<Item> for doctree::OpaqueTy<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: OpaqueTyItem(OpaqueTy { bounds: self.opaque_ty.bounds.clean(cx), @@ -2092,7 +2091,7 @@ impl Clean<Item> for doctree::Static<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: StaticItem(Static { type_: self.type_.clean(cx), @@ -2113,7 +2112,7 @@ impl Clean<Item> for doctree::Constant<'_> { source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: ConstantItem(Constant { type_: self.type_.clean(cx), @@ -2167,7 +2166,7 @@ impl Clean<Vec<Item>> for doctree::Impl<'_> { source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner: ImplItem(Impl { unsafety: self.unsafety, @@ -2349,7 +2348,7 @@ impl Clean<Item> for doctree::ForeignItem<'_> { source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), inner, } @@ -2364,7 +2363,7 @@ impl Clean<Item> for doctree::Macro<'_> { attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: Public, - stability: cx.stability(self.hid).clean(cx), + stability: cx.stability(self.hid), deprecation: cx.deprecation(self.hid).clean(cx), def_id: self.def_id, inner: MacroItem(Macro { @@ -2389,7 +2388,7 @@ impl Clean<Item> for doctree::ProcMacro<'_> { attrs: self.attrs.clean(cx), source: self.span.clean(cx), visibility: Public, - stability: cx.stability(self.id).clean(cx), + stability: cx.stability(self.id), deprecation: cx.deprecation(self.id).clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), inner: ProcMacroItem(ProcMacro { kind: self.kind, helpers: self.helpers.clean(cx) }), @@ -2397,27 +2396,6 @@ impl Clean<Item> for doctree::ProcMacro<'_> { } } -impl Clean<Stability> for attr::Stability { - fn clean(&self, _: &DocContext<'_>) -> Stability { - Stability { - level: stability::StabilityLevel::from_attr_level(&self.level), - feature: self.feature.to_string(), - since: match self.level { - attr::Stable { ref since } => since.to_string(), - _ => String::new(), - }, - unstable_reason: match self.level { - attr::Unstable { reason: Some(ref reason), .. } => Some(reason.to_string()), - _ => None, - }, - issue: match self.level { - attr::Unstable { issue, .. } => issue, - _ => None, - }, - } - } -} - impl Clean<Deprecation> for attr::Deprecation { fn clean(&self, _: &DocContext<'_>) -> Deprecation { Deprecation { diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 903f44a0f93..32b3f69ecd4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -4,7 +4,6 @@ use std::fmt; use std::hash::{Hash, Hasher}; use std::iter::FromIterator; use std::lazy::SyncOnceCell as OnceCell; -use std::num::NonZeroU32; use std::rc::Rc; use std::sync::Arc; use std::{slice, vec}; @@ -12,18 +11,20 @@ use std::{slice, vec}; use rustc_ast::attr; use rustc_ast::util::comments::beautify_doc_string; use rustc_ast::{self as ast, AttrStyle}; +use rustc_ast::{FloatTy, IntTy, UintTy}; +use rustc_attr::{Stability, StabilityLevel}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_hir::Mutability; use rustc_index::vec::IndexVec; -use rustc_middle::middle::stability; use rustc_middle::ty::{AssocKind, TyCtxt}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::DUMMY_SP; -use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::symbol::{kw, sym, Ident, Symbol, SymbolStr}; use rustc_span::{self, FileName}; use rustc_target::abi::VariantIdx; use rustc_target::spec::abi::Abi; @@ -196,7 +197,7 @@ impl Item { self.stability.as_ref().and_then(|ref s| { let mut classes = Vec::with_capacity(2); - if s.level == stability::Unstable { + if s.level.is_unstable() { classes.push("unstable"); } @@ -209,8 +210,11 @@ impl Item { }) } - pub fn stable_since(&self) -> Option<&str> { - self.stability.as_ref().map(|s| &s.since[..]) + pub fn stable_since(&self) -> Option<SymbolStr> { + match self.stability?.level { + StabilityLevel::Stable { since, .. } => Some(since.as_str()), + StabilityLevel::Unstable { .. } => None, + } } pub fn is_non_exhaustive(&self) -> bool { @@ -392,24 +396,6 @@ pub enum DocFragmentKind { /// A doc fragment created from a `#[doc(include="filename")]` attribute. Contains both the /// given filename and the file contents. Include { filename: String }, - /// A doc fragment used to distinguish between documentation in different modules. - /// - /// In particular, this prevents `collapse_docs` from turning all documentation comments - /// into a single giant attributes even when the item is re-exported with documentation on the re-export. - Divider, -} - -impl DocFragment { - /// Creates a dummy doc-fragment which divides earlier and later fragments. - fn divider() -> Self { - DocFragment { - line: 0, - span: DUMMY_SP, - parent_module: None, - doc: String::new(), - kind: DocFragmentKind::Divider, - } - } } impl<'a> FromIterator<&'a DocFragment> for String { @@ -550,7 +536,7 @@ impl Attributes { attrs: &[ast::Attribute], additional_attrs: Option<(&[ast::Attribute], DefId)>, ) -> Attributes { - let doc_strings = RefCell::new(vec![]); + let mut doc_strings = vec![]; let mut sp = None; let mut cfg = Cfg::True; let mut doc_line = 0; @@ -567,7 +553,7 @@ impl Attributes { let line = doc_line; doc_line += value.lines().count(); - doc_strings.borrow_mut().push(DocFragment { + doc_strings.push(DocFragment { line, span: attr.span, doc: value, @@ -592,7 +578,7 @@ impl Attributes { { let line = doc_line; doc_line += contents.lines().count(); - doc_strings.borrow_mut().push(DocFragment { + doc_strings.push(DocFragment { line, span: attr.span, doc: contents, @@ -609,10 +595,7 @@ impl Attributes { // Additional documentation should be shown before the original documentation let other_attrs = additional_attrs .into_iter() - .map(|(attrs, id)| { - doc_strings.borrow_mut().push(DocFragment::divider()); - attrs.iter().map(move |attr| (attr, Some(id))) - }) + .map(|(attrs, id)| attrs.iter().map(move |attr| (attr, Some(id)))) .flatten() .chain(attrs.iter().map(|attr| (attr, None))) .filter_map(clean_attr) @@ -641,7 +624,7 @@ impl Attributes { .map_or(true, |a| a.style == AttrStyle::Inner); Attributes { - doc_strings: doc_strings.into_inner(), + doc_strings, other_attrs, cfg: if cfg == Cfg::True { None } else { Some(Arc::new(cfg)) }, span: sp, @@ -697,9 +680,13 @@ impl Attributes { "../".repeat(depth) } Some(&(_, _, ExternalLocation::Remote(ref s))) => s.to_string(), - Some(&(_, _, ExternalLocation::Unknown)) | None => { - String::from("https://doc.rust-lang.org/nightly") - } + Some(&(_, _, ExternalLocation::Unknown)) | None => String::from( + if UnstableFeatures::from_environment().is_nightly_build() { + "https://doc.rust-lang.org/nightly" + } else { + "https://doc.rust-lang.org" + }, + ), }; // This is a primitive so the url is done "by hand". let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); @@ -1279,6 +1266,28 @@ impl GetDefId for Type { } impl PrimitiveType { + pub fn from_hir(prim: hir::PrimTy) -> PrimitiveType { + match prim { + hir::PrimTy::Int(IntTy::Isize) => PrimitiveType::Isize, + hir::PrimTy::Int(IntTy::I8) => PrimitiveType::I8, + hir::PrimTy::Int(IntTy::I16) => PrimitiveType::I16, + hir::PrimTy::Int(IntTy::I32) => PrimitiveType::I32, + hir::PrimTy::Int(IntTy::I64) => PrimitiveType::I64, + hir::PrimTy::Int(IntTy::I128) => PrimitiveType::I128, + hir::PrimTy::Uint(UintTy::Usize) => PrimitiveType::Usize, + hir::PrimTy::Uint(UintTy::U8) => PrimitiveType::U8, + hir::PrimTy::Uint(UintTy::U16) => PrimitiveType::U16, + hir::PrimTy::Uint(UintTy::U32) => PrimitiveType::U32, + hir::PrimTy::Uint(UintTy::U64) => PrimitiveType::U64, + hir::PrimTy::Uint(UintTy::U128) => PrimitiveType::U128, + hir::PrimTy::Float(FloatTy::F32) => PrimitiveType::F32, + hir::PrimTy::Float(FloatTy::F64) => PrimitiveType::F64, + hir::PrimTy::Str => PrimitiveType::Str, + hir::PrimTy::Bool => PrimitiveType::Bool, + hir::PrimTy::Char => PrimitiveType::Char, + } + } + pub fn from_symbol(s: Symbol) -> Option<PrimitiveType> { match s { sym::isize => Some(PrimitiveType::Isize), @@ -1697,15 +1706,6 @@ pub struct ProcMacro { } #[derive(Clone, Debug)] -pub struct Stability { - pub level: stability::StabilityLevel, - pub feature: String, - pub since: String, - pub unstable_reason: Option<String>, - pub issue: Option<NonZeroU32>, -} - -#[derive(Clone, Debug)] pub struct Deprecation { pub since: Option<String>, pub note: Option<String>, diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 913342e2715..9a7f1964a11 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -3,12 +3,13 @@ use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::{ inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg, GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, Lifetime, - MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type, - TypeBinding, TypeKind, Visibility, WherePredicate, + MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Type, TypeBinding, + TypeKind, Visibility, WherePredicate, }; use crate::core::DocContext; use itertools::Itertools; +use rustc_attr::Stability; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -102,14 +103,14 @@ pub fn krate(mut cx: &mut DocContext<'_>) -> Crate { // extract the stability index for a node from tcx, if possible pub fn get_stability(cx: &DocContext<'_>, def_id: DefId) -> Option<Stability> { - cx.tcx.lookup_stability(def_id).clean(cx) + cx.tcx.lookup_stability(def_id).cloned() } pub fn get_deprecation(cx: &DocContext<'_>, def_id: DefId) -> Option<Deprecation> { cx.tcx.lookup_deprecation(def_id).clean(cx) } -pub fn external_generic_args( +fn external_generic_args( cx: &DocContext<'_>, trait_did: Option<DefId>, has_self: bool, @@ -159,7 +160,7 @@ pub fn external_generic_args( // trait_did should be set to a trait's DefId if called on a TraitRef, in order to sugar // from Fn<(A, B,), C> to Fn(A, B) -> C -pub fn external_path( +pub(super) fn external_path( cx: &DocContext<'_>, name: Symbol, trait_did: Option<DefId>, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 76334f0213d..0608c4e32e0 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -49,6 +49,7 @@ use std::sync::Arc; use itertools::Itertools; use rustc_ast_pretty::pprust; +use rustc_attr::StabilityLevel; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_feature::UnstableFeatures; @@ -575,7 +576,8 @@ impl FormatRenderer for Context { settings( self.shared.static_root_path.as_deref().unwrap_or("./"), &self.shared.resource_suffix, - ), + &self.shared.style_files, + )?, &style_files, ); self.shared.fs.write(&settings_file, v.as_bytes())?; @@ -810,6 +812,7 @@ themePicker.onblur = handleThemeButtonsBlur; but.textContent = item; but.onclick = function(el) {{ switchTheme(currentTheme, mainTheme, item, true); + useSystemTheme(false); }}; but.onblur = handleThemeButtonsBlur; themes.appendChild(but); @@ -1343,22 +1346,35 @@ impl AllTypes { #[derive(Debug)] enum Setting { - Section { description: &'static str, sub_settings: Vec<Setting> }, - Entry { js_data_name: &'static str, description: &'static str, default_value: bool }, + Section { + description: &'static str, + sub_settings: Vec<Setting>, + }, + Toggle { + js_data_name: &'static str, + description: &'static str, + default_value: bool, + }, + Select { + js_data_name: &'static str, + description: &'static str, + default_value: &'static str, + options: Vec<(String, String)>, + }, } impl Setting { - fn display(&self) -> String { + fn display(&self, root_path: &str, suffix: &str) -> String { match *self { - Setting::Section { ref description, ref sub_settings } => format!( + Setting::Section { description, ref sub_settings } => format!( "<div class='setting-line'>\ <div class='title'>{}</div>\ <div class='sub-settings'>{}</div> </div>", description, - sub_settings.iter().map(|s| s.display()).collect::<String>() + sub_settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>() ), - Setting::Entry { ref js_data_name, ref description, ref default_value } => format!( + Setting::Toggle { js_data_name, description, default_value } => format!( "<div class='setting-line'>\ <label class='toggle'>\ <input type='checkbox' id='{}' {}>\ @@ -1367,16 +1383,38 @@ impl Setting { <div>{}</div>\ </div>", js_data_name, - if *default_value { " checked" } else { "" }, + if default_value { " checked" } else { "" }, description, ), + Setting::Select { js_data_name, description, default_value, ref options } => format!( + "<div class=\"setting-line\">\ + <div>{}</div>\ + <label class=\"select-wrapper\">\ + <select id=\"{}\" autocomplete=\"off\">{}</select>\ + <img src=\"{}down-arrow{}.svg\" alt=\"Select item\">\ + </label>\ + </div>", + description, + js_data_name, + options + .iter() + .map(|opt| format!( + "<option value=\"{}\" {}>{}</option>", + opt.0, + if &opt.0 == default_value { "selected" } else { "" }, + opt.1, + )) + .collect::<String>(), + root_path, + suffix, + ), } } } impl From<(&'static str, &'static str, bool)> for Setting { fn from(values: (&'static str, &'static str, bool)) -> Setting { - Setting::Entry { js_data_name: values.0, description: values.1, default_value: values.2 } + Setting::Toggle { js_data_name: values.0, description: values.1, default_value: values.2 } } } @@ -1389,10 +1427,40 @@ impl<T: Into<Setting>> From<(&'static str, Vec<T>)> for Setting { } } -fn settings(root_path: &str, suffix: &str) -> String { +fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<String, Error> { + let theme_names: Vec<(String, String)> = themes + .iter() + .map(|entry| { + let theme = + try_none!(try_none!(entry.path.file_stem(), &entry.path).to_str(), &entry.path) + .to_string(); + + Ok((theme.clone(), theme)) + }) + .collect::<Result<_, Error>>()?; + // (id, explanation, default value) let settings: &[Setting] = &[ ( + "Theme preferences", + vec![ + Setting::from(("use-system-theme", "Use system theme", true)), + Setting::Select { + js_data_name: "preferred-dark-theme", + description: "Preferred dark theme", + default_value: "dark", + options: theme_names.clone(), + }, + Setting::Select { + js_data_name: "preferred-light-theme", + description: "Preferred light theme", + default_value: "light", + options: theme_names, + }, + ], + ) + .into(), + ( "Auto-hide item declarations", vec![ ("auto-hide-struct", "Auto-hide structs declaration", true), @@ -1413,16 +1481,17 @@ fn settings(root_path: &str, suffix: &str) -> String { ("line-numbers", "Show line numbers on code examples", false).into(), ("disable-shortcuts", "Disable keyboard shortcuts", false).into(), ]; - format!( + + Ok(format!( "<h1 class='fqn'>\ - <span class='in-band'>Rustdoc settings</span>\ -</h1>\ -<div class='settings'>{}</div>\ -<script src='{}settings{}.js'></script>", - settings.iter().map(|s| s.display()).collect::<String>(), + <span class='in-band'>Rustdoc settings</span>\ + </h1>\ + <div class='settings'>{}</div>\ + <script src='{}settings{}.js'></script>", + settings.iter().map(|s| s.display(root_path, suffix)).collect::<String>(), root_path, suffix - ) + )) } impl Context { @@ -1762,11 +1831,11 @@ crate fn shorten(s: String) -> String { } } -fn document(w: &mut Buffer, cx: &Context, item: &clean::Item) { +fn document(w: &mut Buffer, cx: &Context, item: &clean::Item, parent: Option<&clean::Item>) { if let Some(ref name) = item.name { info!("Documenting {}", name); } - document_stability(w, cx, item, false); + document_stability(w, cx, item, false, parent); document_full(w, item, cx, "", false); } @@ -1850,8 +1919,14 @@ fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context, prefix: &str, } } -fn document_stability(w: &mut Buffer, cx: &Context, item: &clean::Item, is_hidden: bool) { - let stabilities = short_stability(item, cx); +fn document_stability( + w: &mut Buffer, + cx: &Context, + item: &clean::Item, + is_hidden: bool, + parent: Option<&clean::Item>, +) { + let stabilities = short_stability(item, cx, parent); if !stabilities.is_empty() { write!(w, "<div class='stability{}'>", if is_hidden { " hidden" } else { "" }); for stability in stabilities { @@ -1951,7 +2026,7 @@ pub fn compare_names(mut lhs: &str, mut rhs: &str) -> Ordering { } fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean::Item]) { - document(w, cx, item); + document(w, cx, item, None); let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>(); @@ -1983,10 +2058,12 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: } let s1 = i1.stability.as_ref().map(|s| s.level); let s2 = i2.stability.as_ref().map(|s| s.level); - match (s1, s2) { - (Some(stability::Unstable), Some(stability::Stable)) => return Ordering::Greater, - (Some(stability::Stable), Some(stability::Unstable)) => return Ordering::Less, - _ => {} + if let (Some(a), Some(b)) = (s1, s2) { + match (a.is_stable(), b.is_stable()) { + (true, true) | (false, false) => {} + (false, true) => return Ordering::Less, + (true, false) => return Ordering::Greater, + } } let lhs = i1.name.as_ref().map_or("", |s| &**s); let rhs = i2.name.as_ref().map_or("", |s| &**s); @@ -2108,7 +2185,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: <td class='docblock-short'>{stab_tags}{docs}</td>\ </tr>", name = *myitem.name.as_ref().unwrap(), - stab_tags = stability_tags(myitem), + stab_tags = stability_tags(myitem, item), docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(), class = myitem.type_(), add = add, @@ -2132,7 +2209,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: /// Render the stability and deprecation tags that are displayed in the item's summary at the /// module level. -fn stability_tags(item: &clean::Item) -> String { +fn stability_tags(item: &clean::Item, parent: &clean::Item) -> String { let mut tags = String::new(); fn tag_html(class: &str, title: &str, contents: &str) -> String { @@ -2150,16 +2227,19 @@ fn stability_tags(item: &clean::Item) -> String { // The "rustc_private" crates are permanently unstable so it makes no sense // to render "unstable" everywhere. - if item - .stability - .as_ref() - .map(|s| s.level == stability::Unstable && s.feature != "rustc_private") + if item.stability.as_ref().map(|s| s.level.is_unstable() && s.feature != sym::rustc_private) == Some(true) { tags += &tag_html("unstable", "", "Experimental"); } - if let Some(ref cfg) = item.attrs.cfg { + let cfg = match (&item.attrs.cfg, parent.attrs.cfg.as_ref()) { + (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), + (cfg, _) => cfg.as_deref().cloned(), + }; + + debug!("Portability {:?} - {:?} = {:?}", item.attrs.cfg, parent.attrs.cfg, cfg); + if let Some(ref cfg) = cfg { tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html()); } @@ -2168,7 +2248,7 @@ fn stability_tags(item: &clean::Item) -> String { /// Render the stability and/or deprecation warning that is displayed at the top of the item's /// documentation. -fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { +fn short_stability(item: &clean::Item, cx: &Context, parent: Option<&clean::Item>) -> Vec<String> { let mut stability = vec![]; let error_codes = cx.shared.codes; @@ -2204,16 +2284,17 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { // Render unstable items. But don't render "rustc_private" crates (internal compiler crates). // Those crates are permanently unstable so it makes no sense to render "unstable" everywhere. - if let Some(stab) = item + if let Some((StabilityLevel::Unstable { reason, issue, .. }, feature)) = item .stability .as_ref() - .filter(|stab| stab.level == stability::Unstable && stab.feature != "rustc_private") + .filter(|stab| stab.feature != sym::rustc_private) + .map(|stab| (stab.level, stab.feature)) { let mut message = "<span class='emoji'>🔬</span> This is a nightly-only experimental API.".to_owned(); - let mut feature = format!("<code>{}</code>", Escape(&stab.feature)); - if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, stab.issue) { + let mut feature = format!("<code>{}</code>", Escape(&feature.as_str())); + if let (Some(url), Some(issue)) = (&cx.shared.issue_tracker_base_url, issue) { feature.push_str(&format!( " <a href=\"{url}{issue}\">#{issue}</a>", url = url, @@ -2223,13 +2304,13 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { message.push_str(&format!(" ({})", feature)); - if let Some(unstable_reason) = &stab.unstable_reason { + if let Some(unstable_reason) = reason { let mut ids = cx.id_map.borrow_mut(); message = format!( "<details><summary>{}</summary>{}</details>", message, MarkdownHtml( - &unstable_reason, + &unstable_reason.as_str(), &mut ids, error_codes, cx.shared.edition, @@ -2242,7 +2323,18 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> { stability.push(format!("<div class='stab unstable'>{}</div>", message)); } - if let Some(ref cfg) = item.attrs.cfg { + let cfg = match (&item.attrs.cfg, parent.and_then(|p| p.attrs.cfg.as_ref())) { + (Some(cfg), Some(parent_cfg)) => cfg.simplify_with(parent_cfg), + (cfg, _) => cfg.as_deref().cloned(), + }; + + debug!( + "Portability {:?} - {:?} = {:?}", + item.attrs.cfg, + parent.and_then(|p| p.attrs.cfg.as_ref()), + cfg + ); + if let Some(cfg) = cfg { stability.push(format!("<div class='stab portability'>{}</div>", cfg.render_long_html())); } @@ -2281,7 +2373,7 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons } write!(w, "</pre>"); - document(w, cx, it) + document(w, cx, it, None) } fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static) { @@ -2295,7 +2387,7 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static name = it.name.as_ref().unwrap(), typ = s.type_.print() ); - document(w, cx, it) + document(w, cx, it, None) } fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Function) { @@ -2328,7 +2420,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func .print(), spotlight = spotlight_decl(&f.decl), ); - document(w, cx, it) + document(w, cx, it, None) } fn render_implementor( @@ -2353,9 +2445,10 @@ fn render_implementor( w, cx, implementor, + None, AssocItemLink::Anchor(None), RenderMode::Normal, - implementor.impl_item.stable_since(), + implementor.impl_item.stable_since().as_deref(), false, Some(use_absolute), false, @@ -2382,9 +2475,10 @@ fn render_impls( &mut buffer, cx, i, + Some(containing_item), assoc_link, RenderMode::Normal, - containing_item.stable_since(), + containing_item.stable_since().as_deref(), true, None, false, @@ -2501,7 +2595,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, }); // Trait documentation - document(w, cx, it); + document(w, cx, it, None); fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { write!( @@ -2519,6 +2613,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, fn trait_item(w: &mut Buffer, cx: &Context, m: &clean::Item, t: &clean::Item) { let name = m.name.as_ref().unwrap(); + info!("Documenting {} on {}", name, t.name.as_deref().unwrap_or_default()); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); write!(w, "<h3 id='{id}' class='method'><code>", id = id,); @@ -2526,7 +2621,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, write!(w, "</code>"); render_stability_since(w, m, t); write!(w, "</h3>"); - document(w, cx, m); + document(w, cx, m, Some(t)); } if !types.is_empty() { @@ -2627,9 +2722,10 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, w, cx, &implementor, + None, assoc_link, RenderMode::Normal, - implementor.impl_item.stable_since(), + implementor.impl_item.stable_since().as_deref(), false, None, true, @@ -2780,7 +2876,11 @@ fn render_stability_since_raw(w: &mut Buffer, ver: Option<&str>, containing_ver: } fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: &clean::Item) { - render_stability_since_raw(w, item.stable_since(), containing_item.stable_since()) + render_stability_since_raw( + w, + item.stable_since().as_deref(), + containing_item.stable_since().as_deref(), + ) } fn render_assoc_item( @@ -2885,7 +2985,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct write!(w, "</pre>") }); - document(w, cx, it); + document(w, cx, it, None); let mut fields = s .fields .iter() @@ -2920,7 +3020,7 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct name = field.name.as_ref().unwrap(), ty = ty.print() ); - document(w, cx, field); + document(w, cx, field, Some(it)); } } } @@ -2935,7 +3035,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, write!(w, "</pre>") }); - document(w, cx, it); + document(w, cx, it, None); let mut fields = s .fields .iter() @@ -2967,7 +3067,7 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, if let Some(stability_class) = field.stability_class() { write!(w, "<span class='stab {stab}'></span>", stab = stability_class); } - document(w, cx, field); + document(w, cx, field, Some(it)); } } render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) @@ -3022,7 +3122,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca write!(w, "</pre>") }); - document(w, cx, it); + document(w, cx, it, None); if !e.variants.is_empty() { write!( w, @@ -3055,7 +3155,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca } } write!(w, "</code></div>"); - document(w, cx, variant); + document(w, cx, variant, Some(it)); document_non_exhaustive(w, variant); use crate::clean::{Variant, VariantKind}; @@ -3090,7 +3190,7 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca f = field.name.as_ref().unwrap(), t = ty.print() ); - document(w, cx, field); + document(w, cx, field, Some(variant)); } } write!(w, "</div></div>"); @@ -3288,6 +3388,10 @@ fn render_assoc_items( what: AssocItemRender<'_>, cache: &Cache, ) { + info!( + "Documenting associated items of {}", + containing_item.name.as_deref().unwrap_or_default() + ); let v = match cache.impls.get(&it) { Some(v) => v, None => return, @@ -3322,9 +3426,10 @@ fn render_assoc_items( w, cx, i, + Some(containing_item), AssocItemLink::Anchor(None), render_mode, - containing_item.stable_since(), + containing_item.stable_since().as_deref(), true, None, false, @@ -3513,6 +3618,7 @@ fn render_impl( w: &mut Buffer, cx: &Context, i: &Impl, + parent: Option<&clean::Item>, link: AssocItemLink<'_>, render_mode: RenderMode, outer_version: Option<&str>, @@ -3564,8 +3670,11 @@ fn render_impl( ); } write!(w, "<a href='#{}' class='anchor'></a>", id); - let since = i.impl_item.stability.as_ref().map(|s| &s.since[..]); - render_stability_since_raw(w, since, outer_version); + let since = i.impl_item.stability.as_ref().and_then(|s| match s.level { + StabilityLevel::Stable { since } => Some(since.as_str()), + StabilityLevel::Unstable { .. } => None, + }); + render_stability_since_raw(w, since.as_deref(), outer_version); if let Some(l) = cx.src_href(&i.impl_item, cache) { write!(w, "<a class='srclink' href='{}' title='{}'>[src]</a>", l, "goto source code"); } @@ -3592,6 +3701,7 @@ fn render_impl( w: &mut Buffer, cx: &Context, item: &clean::Item, + parent: Option<&clean::Item>, link: AssocItemLink<'_>, render_mode: RenderMode, is_default_item: bool, @@ -3626,7 +3736,7 @@ fn render_impl( write!(w, "<code>"); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, "</code>"); - render_stability_since_raw(w, item.stable_since(), outer_version); + render_stability_since_raw(w, item.stable_since().as_deref(), outer_version); if let Some(l) = cx.src_href(item, cache) { write!( w, @@ -3648,7 +3758,7 @@ fn render_impl( write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class); assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), ""); write!(w, "</code>"); - render_stability_since_raw(w, item.stable_since(), outer_version); + render_stability_since_raw(w, item.stable_since().as_deref(), outer_version); if let Some(l) = cx.src_href(item, cache) { write!( w, @@ -3676,7 +3786,7 @@ fn render_impl( if let Some(it) = t.items.iter().find(|i| i.name == item.name) { // We need the stability of the item from the trait // because impls can't have a stability. - document_stability(w, cx, it, is_hidden); + document_stability(w, cx, it, is_hidden, parent); if item.doc_value().is_some() { document_full(w, item, cx, "", is_hidden); } else if show_def_docs { @@ -3686,13 +3796,13 @@ fn render_impl( } } } else { - document_stability(w, cx, item, is_hidden); + document_stability(w, cx, item, is_hidden, parent); if show_def_docs { document_full(w, item, cx, "", is_hidden); } } } else { - document_stability(w, cx, item, is_hidden); + document_stability(w, cx, item, is_hidden, parent); if show_def_docs { document_short(w, item, link, "", is_hidden); } @@ -3709,6 +3819,7 @@ fn render_impl( w, cx, trait_item, + parent, link, render_mode, false, @@ -3724,6 +3835,7 @@ fn render_impl( cx: &Context, t: &clean::Trait, i: &clean::Impl, + parent: Option<&clean::Item>, render_mode: RenderMode, outer_version: Option<&str>, show_def_docs: bool, @@ -3741,6 +3853,7 @@ fn render_impl( w, cx, trait_item, + parent, assoc_link, render_mode, true, @@ -3763,6 +3876,7 @@ fn render_impl( cx, t, &i.inner_impl(), + parent, render_mode, outer_version, show_def_docs, @@ -3791,7 +3905,7 @@ fn item_opaque_ty( bounds = bounds(&t.bounds, false) ); - document(w, cx, it); + document(w, cx, it, None); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -3818,7 +3932,7 @@ fn item_trait_alias( bounds(&t.bounds, true) ); - document(w, cx, it); + document(w, cx, it, None); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -3839,7 +3953,7 @@ fn item_typedef(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Typed type_ = t.type_.print() ); - document(w, cx, it); + document(w, cx, it, None); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show @@ -3858,7 +3972,7 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cac it.name.as_ref().unwrap(), ); - document(w, cx, it); + document(w, cx, it, None); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) } @@ -4503,7 +4617,7 @@ fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) None, )) }); - document(w, cx, it) + document(w, cx, it, None) } fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::ProcMacro) { @@ -4533,16 +4647,16 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, m: &clean::Pr write!(w, "</pre>"); } } - document(w, cx, it) + document(w, cx, it, None) } fn item_primitive(w: &mut Buffer, cx: &Context, it: &clean::Item, cache: &Cache) { - document(w, cx, it); + document(w, cx, it, None); render_assoc_items(w, cx, it, it.def_id, AssocItemRender::All, cache) } fn item_keyword(w: &mut Buffer, cx: &Context, it: &clean::Item) { - document(w, cx, it) + document(w, cx, it, None) } crate const BASIC_KEYWORDS: &str = "rust, rustlang, rust-lang"; diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 391526f0a30..a163899839d 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -390,17 +390,13 @@ nav.sub { cursor: pointer; } +.docblock-short { + overflow-wrap: anywhere; +} .docblock-short p { display: inline; } -.docblock-short.nowrap { - display: block; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - .docblock-short p { overflow: hidden; text-overflow: ellipsis; @@ -1544,6 +1540,14 @@ h4 > .notable-traits { left: 0; top: 100%; } + + /* We don't display the help button on mobile devices. */ + .help-button { + display: none; + } + .search-container > div { + width: calc(100% - 32px); + } } @media print { diff --git a/src/librustdoc/html/static/settings.css b/src/librustdoc/html/static/settings.css index d03cf7fcc45..4bacd7b245b 100644 --- a/src/librustdoc/html/static/settings.css +++ b/src/librustdoc/html/static/settings.css @@ -4,7 +4,6 @@ } .setting-line > div { - max-width: calc(100% - 74px); display: inline-block; vertical-align: top; font-size: 17px; @@ -30,6 +29,38 @@ display: none; } +.select-wrapper { + float: right; + position: relative; + height: 27px; + min-width: 25%; +} + +.select-wrapper select { + appearance: none; + -moz-appearance: none; + -webkit-appearance: none; + background: none; + border: 2px solid #ccc; + padding-right: 28px; + width: 100%; +} + +.select-wrapper img { + pointer-events: none; + position: absolute; + right: 0; + bottom: 0; + background: #ccc; + height: 100%; + width: 28px; + padding: 0px 4px; +} + +.select-wrapper select option { + color: initial; +} + .slider { position: absolute; cursor: pointer; diff --git a/src/librustdoc/html/static/settings.js b/src/librustdoc/html/static/settings.js index 427a74c0c87..00a01ac30bc 100644 --- a/src/librustdoc/html/static/settings.js +++ b/src/librustdoc/html/static/settings.js @@ -1,30 +1,56 @@ // Local js definitions: -/* global getCurrentValue, updateLocalStorage */ +/* global getCurrentValue, updateLocalStorage, updateSystemTheme */ (function () { - function changeSetting(settingName, isEnabled) { - updateLocalStorage('rustdoc-' + settingName, isEnabled); + function changeSetting(settingName, value) { + updateLocalStorage("rustdoc-" + settingName, value); + + switch (settingName) { + case "preferred-dark-theme": + case "preferred-light-theme": + case "use-system-theme": + updateSystemTheme(); + break; + } } function getSettingValue(settingName) { - return getCurrentValue('rustdoc-' + settingName); + return getCurrentValue("rustdoc-" + settingName); } function setEvents() { - var elems = document.getElementsByClassName("slider"); - if (!elems || elems.length === 0) { - return; + var elems = { + toggles: document.getElementsByClassName("slider"), + selects: document.getElementsByClassName("select-wrapper") + }; + var i; + + if (elems.toggles && elems.toggles.length > 0) { + for (i = 0; i < elems.toggles.length; ++i) { + var toggle = elems.toggles[i].previousElementSibling; + var settingId = toggle.id; + var settingValue = getSettingValue(settingId); + if (settingValue !== null) { + toggle.checked = settingValue === "true"; + } + toggle.onchange = function() { + changeSetting(this.id, this.checked); + }; + } } - for (var i = 0; i < elems.length; ++i) { - var toggle = elems[i].previousElementSibling; - var settingId = toggle.id; - var settingValue = getSettingValue(settingId); - if (settingValue !== null) { - toggle.checked = settingValue === "true"; + + if (elems.selects && elems.selects.length > 0) { + for (i = 0; i < elems.selects.length; ++i) { + var select = elems.selects[i].getElementsByTagName("select")[0]; + var settingId = select.id; + var settingValue = getSettingValue(settingId); + if (settingValue !== null) { + select.value = settingValue; + } + select.onchange = function() { + changeSetting(this.id, this.value); + }; } - toggle.onchange = function() { - changeSetting(this.id, this.checked); - }; } } diff --git a/src/librustdoc/html/static/storage.js b/src/librustdoc/html/static/storage.js index 0a2fae274fa..a027d6845ea 100644 --- a/src/librustdoc/html/static/storage.js +++ b/src/librustdoc/html/static/storage.js @@ -1,8 +1,10 @@ // From rust: /* global resourcesSuffix */ +var darkThemes = ["dark", "ayu"]; var currentTheme = document.getElementById("themeStyle"); var mainTheme = document.getElementById("mainThemeStyle"); +var localStoredTheme = getCurrentValue("rustdoc-theme"); var savedHref = []; @@ -110,19 +112,90 @@ function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) { }); if (found === true) { styleElem.href = newHref; - // If this new value comes from a system setting or from the previously saved theme, no - // need to save it. + // If this new value comes from a system setting or from the previously + // saved theme, no need to save it. if (saveTheme === true) { updateLocalStorage("rustdoc-theme", newTheme); } } } -function getSystemValue() { - var property = getComputedStyle(document.documentElement).getPropertyValue('content'); - return property.replace(/[\"\']/g, ""); +function useSystemTheme(value) { + if (value === undefined) { + value = true; + } + + updateLocalStorage("rustdoc-use-system-theme", value); + + // update the toggle if we're on the settings page + var toggle = document.getElementById("use-system-theme"); + if (toggle && toggle instanceof HTMLInputElement) { + toggle.checked = value; + } } -switchTheme(currentTheme, mainTheme, - getCurrentValue("rustdoc-theme") || getSystemValue() || "light", - false); +var updateSystemTheme = (function() { + if (!window.matchMedia) { + // fallback to the CSS computed value + return function() { + let cssTheme = getComputedStyle(document.documentElement) + .getPropertyValue('content'); + + switchTheme( + currentTheme, + mainTheme, + JSON.parse(cssTheme) || light, + true + ); + }; + } + + // only listen to (prefers-color-scheme: dark) because light is the default + var mql = window.matchMedia("(prefers-color-scheme: dark)"); + + function handlePreferenceChange(mql) { + // maybe the user has disabled the setting in the meantime! + if (getCurrentValue("rustdoc-use-system-theme") !== "false") { + var lightTheme = getCurrentValue("rustdoc-preferred-light-theme") || "light"; + var darkTheme = getCurrentValue("rustdoc-preferred-dark-theme") || "dark"; + + if (mql.matches) { + // prefers a dark theme + switchTheme(currentTheme, mainTheme, darkTheme, true); + } else { + // prefers a light theme, or has no preference + switchTheme(currentTheme, mainTheme, lightTheme, true); + } + + // note: we save the theme so that it doesn't suddenly change when + // the user disables "use-system-theme" and reloads the page or + // navigates to another page + } + } + + mql.addListener(handlePreferenceChange); + + return function() { + handlePreferenceChange(mql); + }; +})(); + +if (getCurrentValue("rustdoc-use-system-theme") !== "false" && window.matchMedia) { + // update the preferred dark theme if the user is already using a dark theme + // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732 + if (getCurrentValue("rustdoc-use-system-theme") === null + && getCurrentValue("rustdoc-preferred-dark-theme") === null + && darkThemes.indexOf(localStoredTheme) >= 0) { + updateLocalStorage("rustdoc-preferred-dark-theme", localStoredTheme); + } + + // call the function to initialize the theme at least once! + updateSystemTheme(); +} else { + switchTheme( + currentTheme, + mainTheme, + getCurrentValue("rustdoc-theme") || "light", + false + ); +} diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 7762e8f8d4f..12726d2bd9a 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -3,11 +3,13 @@ html_playground_url = "https://play.rust-lang.org/" )] #![feature(rustc_private)] +#![feature(array_methods)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] +#![feature(peekable_next_if)] #![feature(test)] #![feature(crate_visibility_modifier)] #![feature(never_type)] diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 4bca3996eb4..ced26fcf5b0 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -1,10 +1,12 @@ use crate::clean; -use crate::config::OutputFormat; use crate::core::DocContext; use crate::fold::{self, DocFolder}; use crate::html::markdown::{find_testable_code, ErrorCodes}; use crate::passes::doc_test_lints::{should_have_doc_example, Tests}; use crate::passes::Pass; +use rustc_lint::builtin::MISSING_DOCS; +use rustc_middle::lint::LintSource; +use rustc_session::lint; use rustc_span::symbol::sym; use rustc_span::FileName; use serde::Serialize; @@ -19,10 +21,10 @@ pub const CALCULATE_DOC_COVERAGE: Pass = Pass { }; fn calculate_doc_coverage(krate: clean::Crate, ctx: &DocContext<'_>) -> clean::Crate { - let mut calc = CoverageCalculator::new(); + let mut calc = CoverageCalculator::new(ctx); let krate = calc.fold_crate(krate); - calc.print_results(ctx.renderinfo.borrow().output_format); + calc.print_results(); krate } @@ -41,8 +43,11 @@ impl ItemCount { has_docs: bool, has_doc_example: bool, should_have_doc_examples: bool, + should_have_docs: bool, ) { - self.total += 1; + if has_docs || should_have_docs { + self.total += 1; + } if has_docs { self.with_docs += 1; @@ -94,8 +99,9 @@ impl ops::AddAssign for ItemCount { } } -struct CoverageCalculator { +struct CoverageCalculator<'a, 'b> { items: BTreeMap<FileName, ItemCount>, + ctx: &'a DocContext<'b>, } fn limit_filename_len(filename: String) -> String { @@ -108,9 +114,9 @@ fn limit_filename_len(filename: String) -> String { } } -impl CoverageCalculator { - fn new() -> CoverageCalculator { - CoverageCalculator { items: Default::default() } +impl<'a, 'b> CoverageCalculator<'a, 'b> { + fn new(ctx: &'a DocContext<'b>) -> CoverageCalculator<'a, 'b> { + CoverageCalculator { items: Default::default(), ctx } } fn to_json(&self) -> String { @@ -124,7 +130,8 @@ impl CoverageCalculator { .expect("failed to convert JSON data to string") } - fn print_results(&self, output_format: Option<OutputFormat>) { + fn print_results(&self) { + let output_format = self.ctx.renderinfo.borrow().output_format; if output_format.map(|o| o.is_json()).unwrap_or_else(|| false) { println!("{}", self.to_json()); return; @@ -178,7 +185,7 @@ impl CoverageCalculator { } } -impl fold::DocFolder for CoverageCalculator { +impl<'a, 'b> fold::DocFolder for CoverageCalculator<'a, 'b> { fn fold_item(&mut self, i: clean::Item) -> Option<clean::Item> { match i.inner { _ if !i.def_id.is_local() => { @@ -245,11 +252,18 @@ impl fold::DocFolder for CoverageCalculator { ); let has_doc_example = tests.found_tests != 0; + let hir_id = self.ctx.tcx.hir().local_def_id_to_hir_id(i.def_id.expect_local()); + let (level, source) = self.ctx.tcx.lint_level_at_node(MISSING_DOCS, hir_id); + // `missing_docs` is allow-by-default, so don't treat this as ignoring the item + // unless the user had an explicit `allow` + let should_have_docs = + level != lint::Level::Allow || matches!(source, LintSource::Default); debug!("counting {:?} {:?} in {}", i.type_(), i.name, i.source.filename); self.items.entry(i.source.filename.clone()).or_default().count_item( has_docs, has_doc_example, - should_have_doc_example(&i.inner), + should_have_doc_example(self.ctx, &i), + should_have_docs, ); } } diff --git a/src/librustdoc/passes/collapse_docs.rs b/src/librustdoc/passes/collapse_docs.rs index be7250f833f..c2f7f97a673 100644 --- a/src/librustdoc/passes/collapse_docs.rs +++ b/src/librustdoc/passes/collapse_docs.rs @@ -36,7 +36,10 @@ fn collapse(doc_strings: &mut Vec<DocFragment>) { let curr_kind = &curr_frag.kind; let new_kind = &frag.kind; - if matches!(*curr_kind, DocFragmentKind::Include { .. }) || curr_kind != new_kind { + if matches!(*curr_kind, DocFragmentKind::Include { .. }) + || curr_kind != new_kind + || curr_frag.parent_module != frag.parent_module + { if *curr_kind == DocFragmentKind::SugaredDoc || *curr_kind == DocFragmentKind::RawDoc { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5b5624298a4..8be9482acff 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -16,6 +16,7 @@ use rustc_session::lint::{ Lint, }; use rustc_span::hygiene::MacroKind; +use rustc_span::symbol::sym; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; @@ -23,6 +24,7 @@ use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; use std::cell::Cell; +use std::mem; use std::ops::Range; use crate::clean::*; @@ -65,10 +67,53 @@ enum ResolutionFailure<'a> { NotResolved { module_id: DefId, partial_res: Option<Res>, unresolved: Cow<'a, str> }, /// should not ever happen NoParentItem, + /// This link has malformed generic parameters; e.g., the angle brackets are unbalanced. + MalformedGenerics(MalformedGenerics), /// used to communicate that this should be ignored, but shouldn't be reported to the user Dummy, } +#[derive(Debug)] +enum MalformedGenerics { + /// This link has unbalanced angle brackets. + /// + /// For example, `Vec<T` should trigger this, as should `Vec<T>>`. + UnbalancedAngleBrackets, + /// The generics are not attached to a type. + /// + /// For example, `<T>` should trigger this. + /// + /// This is detected by checking if the path is empty after the generics are stripped. + MissingType, + /// The link uses fully-qualified syntax, which is currently unsupported. + /// + /// For example, `<Vec as IntoIterator>::into_iter` should trigger this. + /// + /// This is detected by checking if ` as ` (the keyword `as` with spaces around it) is inside + /// angle brackets. + HasFullyQualifiedSyntax, + /// The link has an invalid path separator. + /// + /// For example, `Vec:<T>:new()` should trigger this. Note that `Vec:new()` will **not** + /// trigger this because it has no generics and thus [`strip_generics_from_path`] will not be + /// called. + /// + /// Note that this will also **not** be triggered if the invalid path separator is inside angle + /// brackets because rustdoc mostly ignores what's inside angle brackets (except for + /// [`HasFullyQualifiedSyntax`](MalformedGenerics::HasFullyQualifiedSyntax)). + /// + /// This is detected by checking if there is a colon followed by a non-colon in the link. + InvalidPathSeparator, + /// The link has too many angle brackets. + /// + /// For example, `Vec<<T>>` should trigger this. + TooManyAngleBrackets, + /// The link has empty angle brackets. + /// + /// For example, `Vec<>` should trigger this. + EmptyAngleBrackets, +} + impl ResolutionFailure<'a> { // This resolved fully (not just partially) but is erroneous for some other reason fn full_res(&self) -> Option<Res> { @@ -190,6 +235,56 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } } + fn resolve_primitive_associated_item( + &self, + prim_ty: hir::PrimTy, + ns: Namespace, + module_id: DefId, + item_name: Symbol, + item_str: &'path str, + ) -> Result<(Res, Option<String>), ErrorKind<'path>> { + let cx = self.cx; + + PrimitiveType::from_hir(prim_ty) + .impls(cx.tcx) + .into_iter() + .find_map(|&impl_| { + cx.tcx + .associated_items(impl_) + .find_by_name_and_namespace( + cx.tcx, + Ident::with_dummy_span(item_name), + ns, + impl_, + ) + .map(|item| match item.kind { + ty::AssocKind::Fn => "method", + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + }) + .map(|out| { + ( + Res::PrimTy(prim_ty), + Some(format!("{}#{}.{}", prim_ty.name(), out, item_str)), + ) + }) + }) + .ok_or_else(|| { + debug!( + "returning primitive error for {}::{} in {} namespace", + prim_ty.name(), + item_name, + ns.descr() + ); + ResolutionFailure::NotResolved { + module_id, + partial_res: Some(Res::PrimTy(prim_ty)), + unresolved: item_str.into(), + } + .into() + }) + } + /// Resolves a string as a macro. fn macro_resolve( &self, @@ -231,6 +326,19 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { }) } + fn resolve_path(&self, path_str: &str, ns: Namespace, module_id: DefId) -> Option<Res> { + let result = self.cx.enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) + }); + debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); + match result.map(|(_, res)| res) { + // resolver doesn't know about true and false so we'll have to resolve them + // manually as bool + Ok(Res::Err) | Err(()) => is_bool_value(path_str, ns).map(|(_, res)| res), + Ok(res) => Some(res.map_id(|_| panic!("unexpected node_id"))), + } + } + /// Resolves a string as a path within a particular namespace. Also returns an optional /// URL fragment in the case of variants and methods. fn resolve<'path>( @@ -243,22 +351,18 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ) -> Result<(Res, Option<String>), ErrorKind<'path>> { let cx = self.cx; - let result = cx.enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) - }); - debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); - let result = match result { - Ok((_, Res::Err)) => Err(()), - x => x, - }; - - if let Ok((_, res)) = result { - let res = res.map_id(|_| panic!("unexpected node_id")); - // In case this is a trait item, skip the - // early return and try looking for the trait. - let value = match res { - Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true, - Res::Def(DefKind::AssocTy, _) => false, + if let Some(res) = self.resolve_path(path_str, ns, module_id) { + match res { + Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => { + assert_eq!(ns, ValueNS); + // Fall through: In case this is a trait item, skip the + // early return and try looking for the trait. + } + Res::Def(DefKind::AssocTy, _) => { + assert_eq!(ns, TypeNS); + // Fall through: In case this is a trait item, skip the + // early return and try looking for the trait. + } Res::Def(DefKind::Variant, _) => { return handle_variant(cx, res, extra_fragment); } @@ -277,17 +381,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => { return Ok((res, extra_fragment.clone())); } - }; - - if value != (ns == ValueNS) { - return Err(ResolutionFailure::WrongNamespace(res, ns).into()); - } - // FIXME: why is this necessary? - } else if let Some((path, prim)) = is_primitive(path_str, ns) { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim))); } - return Ok((prim, Some(path.to_owned()))); } // Try looking for methods and associated items. @@ -315,70 +409,30 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } })?; - if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { - let impls = - primitive_impl(cx, &path).ok_or_else(|| ResolutionFailure::NotResolved { + // FIXME: are these both necessary? + let ty_res = if let Some(ty_res) = is_primitive(&path_root, TypeNS) + .map(|(_, res)| res) + .or_else(|| self.resolve_path(&path_root, TypeNS, module_id)) + { + ty_res + } else { + // FIXME: this is duplicated on the end of this function. + return if ns == Namespace::ValueNS { + self.variant_field(path_str, current_item, module_id) + } else { + Err(ResolutionFailure::NotResolved { module_id, - partial_res: Some(prim), - unresolved: item_str.into(), - })?; - for &impl_ in impls { - let link = cx - .tcx - .associated_items(impl_) - .find_by_name_and_namespace( - cx.tcx, - Ident::with_dummy_span(item_name), - ns, - impl_, - ) - .map(|item| match item.kind { - ty::AssocKind::Fn => "method", - ty::AssocKind::Const => "associatedconstant", - ty::AssocKind::Type => "associatedtype", - }) - .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_str)))); - if let Some(link) = link { - return Ok(link); + partial_res: None, + unresolved: path_root.into(), } - } - debug!( - "returning primitive error for {}::{} in {} namespace", - path, - item_name, - ns.descr() - ); - return Err(ResolutionFailure::NotResolved { - module_id, - partial_res: Some(prim), - unresolved: item_str.into(), - } - .into()); - } - - let ty_res = cx - .enter_resolver(|resolver| { - // only types can have associated items - resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) - }) - .map(|(_, res)| res); - let ty_res = match ty_res { - Err(()) | Ok(Res::Err) => { - return if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id) - } else { - Err(ResolutionFailure::NotResolved { - module_id, - partial_res: None, - unresolved: path_root.into(), - } - .into()) - }; - } - Ok(res) => res, + .into()) + }; }; - let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); + let res = match ty_res { + Res::PrimTy(prim) => Some( + self.resolve_primitive_associated_item(prim, ns, module_id, item_name, item_str), + ), Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => { debug!("looking for associated item named {} for item {:?}", item_name, did); // Checks if item_name belongs to `impl SomeItem` @@ -418,7 +472,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { Some(if extra_fragment.is_some() { Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res))) } else { - // HACK(jynelson): `clean` expects the type, not the associated item. + // HACK(jynelson): `clean` expects the type, not the associated item // but the disambiguator logic expects the associated item. // Store the kind in a side channel so that only the disambiguator logic looks at it. self.kind_side_channel.set(Some((kind.as_def_kind(), id))); @@ -464,13 +518,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { _ => None, } } else { - // We already know this isn't in ValueNS, so no need to check variant_field - return Err(ResolutionFailure::NotResolved { - module_id, - partial_res: Some(ty_res), - unresolved: item_str.into(), - } - .into()); + None } } Res::Def(DefKind::Trait, did) => cx @@ -527,30 +575,21 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { current_item: &Option<String>, extra_fragment: &Option<String>, ) -> Option<Res> { - let check_full_res_inner = |this: &Self, result: Result<Res, ErrorKind<'_>>| { - let res = match result { - Ok(res) => Some(res), - Err(ErrorKind::Resolve(box kind)) => kind.full_res(), - Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => { - Some(res) - } - Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, - }; - this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) + // resolve() can't be used for macro namespace + let result = match ns { + Namespace::MacroNS => self.macro_resolve(path_str, module_id).map_err(ErrorKind::from), + Namespace::TypeNS | Namespace::ValueNS => self + .resolve(path_str, ns, current_item, module_id, extra_fragment) + .map(|(res, _)| res), }; - // cannot be used for macro namespace - let check_full_res = |this: &Self, ns| { - let result = this.resolve(path_str, ns, current_item, module_id, extra_fragment); - check_full_res_inner(this, result.map(|(res, _)| res)) - }; - let check_full_res_macro = |this: &Self| { - let result = this.macro_resolve(path_str, module_id); - check_full_res_inner(this, result.map_err(ErrorKind::from)) + + let res = match result { + Ok(res) => Some(res), + Err(ErrorKind::Resolve(box kind)) => kind.full_res(), + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => Some(res), + Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, }; - match ns { - Namespace::MacroNS => check_full_res_macro(self), - Namespace::TypeNS | Namespace::ValueNS => check_full_res(self, ns), - } + self.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) } } @@ -650,14 +689,9 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx let ty = cx.tcx.type_of(type_); let iter = in_scope_traits.iter().flat_map(|&trait_| { trace!("considering explicit impl for trait {:?}", trait_); - let mut saw_impl = false; - // Look at each trait implementation to see if it's an impl for `did` - cx.tcx.for_each_relevant_impl(trait_, ty, |impl_| { - // FIXME: this is inefficient, find a way to short-circuit for_each_* so this doesn't take as long - if saw_impl { - return; - } + // Look at each trait implementation to see if it's an impl for `did` + cx.tcx.find_map_relevant_impl(trait_, ty, |impl_| { let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl"); // Check if these are the same type. let impl_type = trait_ref.self_ty(); @@ -668,7 +702,7 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx type_ ); // Fast path: if this is a primitive simple `==` will work - saw_impl = impl_type == ty + let saw_impl = impl_type == ty || match impl_type.kind() { // Check if these are the same def_id ty::Adt(def, _) => { @@ -678,8 +712,9 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx ty::Foreign(def_id) => *def_id == type_, _ => false, }; - }); - if saw_impl { Some(trait_) } else { None } + + if saw_impl { Some(trait_) } else { None } + }) }); iter.collect() } @@ -912,6 +947,7 @@ impl LinkCollector<'_, '_> { let link_text; let mut path_str; let disambiguator; + let stripped_path_string; let (mut res, mut fragment) = { path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { disambiguator = Some(d); @@ -922,7 +958,7 @@ impl LinkCollector<'_, '_> { } .trim(); - if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) { + if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ":_<>, ".contains(ch))) { return None; } @@ -985,6 +1021,36 @@ impl LinkCollector<'_, '_> { module_id = DefId { krate, index: CRATE_DEF_INDEX }; } + // Strip generics from the path. + if path_str.contains(['<', '>'].as_slice()) { + stripped_path_string = match strip_generics_from_path(path_str) { + Ok(path) => path, + Err(err_kind) => { + debug!("link has malformed generics: {}", path_str); + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![err_kind], + ); + return None; + } + }; + path_str = &stripped_path_string; + } + + // Sanity check to make sure we don't have any angle brackets after stripping generics. + assert!(!path_str.contains(['<', '>'].as_slice())); + + // The link is not an intra-doc link if it still contains commas or spaces after + // stripping generics. + if path_str.contains([',', ' '].as_slice()) { + return None; + } + match self.resolve_with_disambiguator( disambiguator, item, @@ -1024,7 +1090,7 @@ impl LinkCollector<'_, '_> { return None; } res = prim; - fragment = Some(path.to_owned()); + fragment = Some(path.as_str().to_string()); } else { // `[char]` when a `char` module is in scope let candidates = vec![res, prim]; @@ -1718,6 +1784,27 @@ fn resolution_failure( diag.level = rustc_errors::Level::Bug; "all intra doc links should have a parent item".to_owned() } + ResolutionFailure::MalformedGenerics(variant) => match variant { + MalformedGenerics::UnbalancedAngleBrackets => { + String::from("unbalanced angle brackets") + } + MalformedGenerics::MissingType => { + String::from("missing type for generic parameters") + } + MalformedGenerics::HasFullyQualifiedSyntax => { + diag.note("see https://github.com/rust-lang/rust/issues/74563 for more information"); + String::from("fully-qualified syntax is unsupported") + } + MalformedGenerics::InvalidPathSeparator => { + String::from("has invalid path separator") + } + MalformedGenerics::TooManyAngleBrackets => { + String::from("too many angle brackets") + } + MalformedGenerics::EmptyAngleBrackets => { + String::from("empty angle brackets") + } + }, }; if let Some(span) = sp { diag.span_label(span, ¬e); @@ -1860,51 +1947,158 @@ fn handle_variant( if extra_fragment.is_some() { return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))); } - let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { - parent - } else { - return Err(ResolutionFailure::NoParentItem.into()); - }; - let parent_def = Res::Def(DefKind::Enum, parent); - let variant = cx.tcx.expect_variant_res(res); - Ok((parent_def, Some(format!("variant.{}", variant.ident.name)))) + cx.tcx + .parent(res.def_id()) + .map(|parent| { + let parent_def = Res::Def(DefKind::Enum, parent); + let variant = cx.tcx.expect_variant_res(res); + (parent_def, Some(format!("variant.{}", variant.ident.name))) + }) + .ok_or_else(|| ResolutionFailure::NoParentItem.into()) } -const PRIMITIVES: &[(&str, Res)] = &[ - ("u8", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U8))), - ("u16", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U16))), - ("u32", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U32))), - ("u64", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U64))), - ("u128", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U128))), - ("usize", Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::Usize))), - ("i8", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I8))), - ("i16", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I16))), - ("i32", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I32))), - ("i64", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I64))), - ("i128", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I128))), - ("isize", Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::Isize))), - ("f32", Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F32))), - ("f64", Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))), - ("str", Res::PrimTy(hir::PrimTy::Str)), - ("bool", Res::PrimTy(hir::PrimTy::Bool)), - ("true", Res::PrimTy(hir::PrimTy::Bool)), - ("false", Res::PrimTy(hir::PrimTy::Bool)), - ("char", Res::PrimTy(hir::PrimTy::Char)), +// FIXME: At this point, this is basically a copy of the PrimitiveTypeTable +const PRIMITIVES: &[(Symbol, Res)] = &[ + (sym::u8, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U8))), + (sym::u16, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U16))), + (sym::u32, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U32))), + (sym::u64, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U64))), + (sym::u128, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::U128))), + (sym::usize, Res::PrimTy(hir::PrimTy::Uint(rustc_ast::UintTy::Usize))), + (sym::i8, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I8))), + (sym::i16, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I16))), + (sym::i32, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I32))), + (sym::i64, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I64))), + (sym::i128, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::I128))), + (sym::isize, Res::PrimTy(hir::PrimTy::Int(rustc_ast::IntTy::Isize))), + (sym::f32, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F32))), + (sym::f64, Res::PrimTy(hir::PrimTy::Float(rustc_ast::FloatTy::F64))), + (sym::str, Res::PrimTy(hir::PrimTy::Str)), + (sym::bool, Res::PrimTy(hir::PrimTy::Bool)), + (sym::char, Res::PrimTy(hir::PrimTy::Char)), ]; -fn is_primitive(path_str: &str, ns: Namespace) -> Option<(&'static str, Res)> { - if ns == TypeNS { - PRIMITIVES - .iter() - .filter(|x| x.0 == path_str) - .copied() - .map(|x| if x.0 == "true" || x.0 == "false" { ("bool", x.1) } else { x }) - .next() +fn is_primitive(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> { + is_bool_value(path_str, ns).or_else(|| { + if ns == TypeNS { + // FIXME: this should be replaced by a lookup in PrimitiveTypeTable + let maybe_primitive = Symbol::intern(path_str); + PRIMITIVES.iter().find(|x| x.0 == maybe_primitive).copied() + } else { + None + } + }) +} + +fn is_bool_value(path_str: &str, ns: Namespace) -> Option<(Symbol, Res)> { + if ns == TypeNS && (path_str == "true" || path_str == "false") { + Some((sym::bool, Res::PrimTy(hir::PrimTy::Bool))) } else { None } } -fn primitive_impl(cx: &DocContext<'_>, path_str: &str) -> Option<&'static SmallVec<[DefId; 4]>> { - Some(PrimitiveType::from_symbol(Symbol::intern(path_str))?.impls(cx.tcx)) +fn strip_generics_from_path(path_str: &str) -> Result<String, ResolutionFailure<'static>> { + let mut stripped_segments = vec![]; + let mut path = path_str.chars().peekable(); + let mut segment = Vec::new(); + + while let Some(chr) = path.next() { + match chr { + ':' => { + if path.next_if_eq(&':').is_some() { + let stripped_segment = + strip_generics_from_path_segment(mem::take(&mut segment))?; + if !stripped_segment.is_empty() { + stripped_segments.push(stripped_segment); + } + } else { + return Err(ResolutionFailure::MalformedGenerics( + MalformedGenerics::InvalidPathSeparator, + )); + } + } + '<' => { + segment.push(chr); + + match path.next() { + Some('<') => { + return Err(ResolutionFailure::MalformedGenerics( + MalformedGenerics::TooManyAngleBrackets, + )); + } + Some('>') => { + return Err(ResolutionFailure::MalformedGenerics( + MalformedGenerics::EmptyAngleBrackets, + )); + } + Some(chr) => { + segment.push(chr); + + while let Some(chr) = path.next_if(|c| *c != '>') { + segment.push(chr); + } + } + None => break, + } + } + _ => segment.push(chr), + } + debug!("raw segment: {:?}", segment); + } + + if !segment.is_empty() { + let stripped_segment = strip_generics_from_path_segment(segment)?; + if !stripped_segment.is_empty() { + stripped_segments.push(stripped_segment); + } + } + + debug!("path_str: {:?}\nstripped segments: {:?}", path_str, &stripped_segments); + + let stripped_path = stripped_segments.join("::"); + + if !stripped_path.is_empty() { + Ok(stripped_path) + } else { + Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::MissingType)) + } +} + +fn strip_generics_from_path_segment( + segment: Vec<char>, +) -> Result<String, ResolutionFailure<'static>> { + let mut stripped_segment = String::new(); + let mut param_depth = 0; + + let mut latest_generics_chunk = String::new(); + + for c in segment { + if c == '<' { + param_depth += 1; + latest_generics_chunk.clear(); + } else if c == '>' { + param_depth -= 1; + if latest_generics_chunk.contains(" as ") { + // The segment tries to use fully-qualified syntax, which is currently unsupported. + // Give a helpful error message instead of completely ignoring the angle brackets. + return Err(ResolutionFailure::MalformedGenerics( + MalformedGenerics::HasFullyQualifiedSyntax, + )); + } + } else { + if param_depth == 0 { + stripped_segment.push(c); + } else { + latest_generics_chunk.push(c); + } + } + } + + if param_depth == 0 { + Ok(stripped_segment) + } else { + // The segment has unbalanced angle brackets, e.g. `Vec<T` or `Vec<T>>` + Err(ResolutionFailure::MalformedGenerics(MalformedGenerics::UnbalancedAngleBrackets)) + } } diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 78af9f9b856..686ec51fb06 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -9,6 +9,7 @@ use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; +use rustc_middle::lint::LintSource; use rustc_session::lint; pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { @@ -56,8 +57,8 @@ impl crate::doctest::Tester for Tests { } } -pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool { - !matches!(item_kind, +pub fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool { + if matches!(item.inner, clean::StructFieldItem(_) | clean::VariantItem(_) | clean::AssocConstItem(_, _) @@ -69,7 +70,13 @@ pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool { | clean::ImportItem(_) | clean::PrimitiveItem(_) | clean::KeywordItem(_) - ) + ) { + return false; + } + let hir_id = cx.tcx.hir().local_def_id_to_hir_id(item.def_id.expect_local()); + let (level, source) = + cx.tcx.lint_level_at_node(lint::builtin::MISSING_DOC_CODE_EXAMPLES, hir_id); + level != lint::Level::Allow || matches!(source, LintSource::Default) } pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { @@ -88,7 +95,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { if tests.found_tests == 0 && rustc_feature::UnstableFeatures::from_environment().is_nightly_build() { - if should_have_doc_example(&item.inner) { + if should_have_doc_example(cx, &item) { debug!("reporting error for {:?} (hir_id={:?})", item, hir_id); let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span()); cx.tcx.struct_span_lint_hir( diff --git a/src/librustdoc/passes/html_tags.rs b/src/librustdoc/passes/html_tags.rs index ae4eac89b45..1d9be619ec9 100644 --- a/src/librustdoc/passes/html_tags.rs +++ b/src/librustdoc/passes/html_tags.rs @@ -7,6 +7,8 @@ use core::ops::Range; use pulldown_cmark::{Event, Parser}; use rustc_feature::UnstableFeatures; use rustc_session::lint; +use std::iter::Peekable; +use std::str::CharIndices; pub const CHECK_INVALID_HTML_TAGS: Pass = Pass { name: "check-invalid-html-tags", @@ -75,70 +77,97 @@ fn drop_tag( } } -fn extract_tag( +fn extract_html_tag( tags: &mut Vec<(String, Range<usize>)>, text: &str, - range: Range<usize>, + range: &Range<usize>, + start_pos: usize, + iter: &mut Peekable<CharIndices<'_>>, f: &impl Fn(&str, &Range<usize>), ) { - let mut iter = text.char_indices().peekable(); + let mut tag_name = String::new(); + let mut is_closing = false; + let mut prev_pos = start_pos; - while let Some((start_pos, c)) = iter.next() { - if c == '<' { - let mut tag_name = String::new(); - let mut is_closing = false; - let mut prev_pos = start_pos; - loop { - let (pos, c) = match iter.peek() { - Some((pos, c)) => (*pos, *c), - // In case we reached the of the doc comment, we want to check that it's an - // unclosed HTML tag. For example "/// <h3". - None => (prev_pos, '\0'), - }; - prev_pos = pos; - // Checking if this is a closing tag (like `</a>` for `<a>`). - if c == '/' && tag_name.is_empty() { - is_closing = true; - } else if c.is_ascii_alphanumeric() { - tag_name.push(c); - } else { - if !tag_name.is_empty() { - let mut r = - Range { start: range.start + start_pos, end: range.start + pos }; - if c == '>' { - // In case we have a tag without attribute, we can consider the span to - // refer to it fully. - r.end += 1; + loop { + let (pos, c) = match iter.peek() { + Some((pos, c)) => (*pos, *c), + // In case we reached the of the doc comment, we want to check that it's an + // unclosed HTML tag. For example "/// <h3". + None => (prev_pos, '\0'), + }; + prev_pos = pos; + // Checking if this is a closing tag (like `</a>` for `<a>`). + if c == '/' && tag_name.is_empty() { + is_closing = true; + } else if c.is_ascii_alphanumeric() { + tag_name.push(c); + } else { + if !tag_name.is_empty() { + let mut r = Range { start: range.start + start_pos, end: range.start + pos }; + if c == '>' { + // In case we have a tag without attribute, we can consider the span to + // refer to it fully. + r.end += 1; + } + if is_closing { + // In case we have "</div >" or even "</div >". + if c != '>' { + if !c.is_whitespace() { + // It seems like it's not a valid HTML tag. + break; } - if is_closing { - // In case we have "</div >" or even "</div >". - if c != '>' { - if !c.is_whitespace() { - // It seems like it's not a valid HTML tag. - break; - } - let mut found = false; - for (new_pos, c) in text[pos..].char_indices() { - if !c.is_whitespace() { - if c == '>' { - r.end = range.start + new_pos + 1; - found = true; - } - break; - } - } - if !found { - break; + let mut found = false; + for (new_pos, c) in text[pos..].char_indices() { + if !c.is_whitespace() { + if c == '>' { + r.end = range.start + new_pos + 1; + found = true; } + break; } - drop_tag(tags, tag_name, r, f); - } else { - tags.push((tag_name, r)); + } + if !found { + break; } } - break; + drop_tag(tags, tag_name, r, f); + } else { + tags.push((tag_name, r)); } + } + break; + } + iter.next(); + } +} + +fn extract_tags( + tags: &mut Vec<(String, Range<usize>)>, + text: &str, + range: Range<usize>, + is_in_comment: &mut Option<Range<usize>>, + f: &impl Fn(&str, &Range<usize>), +) { + let mut iter = text.char_indices().peekable(); + + while let Some((start_pos, c)) = iter.next() { + if is_in_comment.is_some() { + if text[start_pos..].starts_with("-->") { + *is_in_comment = None; + } + } else if c == '<' { + if text[start_pos..].starts_with("<!--") { + // We skip the "!--" part. (Once `advance_by` is stable, might be nice to use it!) + iter.next(); iter.next(); + iter.next(); + *is_in_comment = Some(Range { + start: range.start + start_pos, + end: range.start + start_pos + 3, + }); + } else { + extract_html_tag(tags, text, &range, start_pos, &mut iter, f); } } } @@ -167,12 +196,15 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { }; let mut tags = Vec::new(); + let mut is_in_comment = None; let p = Parser::new_ext(&dox, opts()).into_offset_iter(); for (event, range) in p { match event { - Event::Html(text) => extract_tag(&mut tags, &text, range, &report_diag), + Event::Html(text) | Event::Text(text) => { + extract_tags(&mut tags, &text, range, &mut is_in_comment, &report_diag) + } _ => {} } } @@ -183,6 +215,10 @@ impl<'a, 'tcx> DocFolder for InvalidHtmlTagsLinter<'a, 'tcx> { }) { report_diag(&format!("unclosed HTML tag `{}`", tag), range); } + + if let Some(range) = is_in_comment { + report_diag("Unclosed HTML comment", &range); + } } self.fold_item_recur(item) diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 39c61f7edbe..2591650e3f9 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -1,16 +1,15 @@ //! Contains information about "passes", used to modify crate information during the documentation //! process. -use rustc_hir::def_id::{DefId, DefIdSet}; -use rustc_middle::middle::privacy::AccessLevels; use rustc_span::{InnerSpan, Span, DUMMY_SP}; -use std::mem; use std::ops::Range; use self::Condition::*; -use crate::clean::{self, DocFragmentKind, GetDefId, Item}; +use crate::clean::{self, DocFragmentKind}; use crate::core::DocContext; -use crate::fold::{DocFolder, StripItem}; + +mod stripper; +pub use stripper::*; mod collapse_docs; pub use self::collapse_docs::COLLAPSE_DOCS; @@ -149,171 +148,6 @@ pub fn find_pass(pass_name: &str) -> Option<Pass> { PASSES.iter().find(|p| p.name == pass_name).copied() } -struct Stripper<'a> { - retained: &'a mut DefIdSet, - access_levels: &'a AccessLevels<DefId>, - update_retained: bool, -} - -impl<'a> DocFolder for Stripper<'a> { - fn fold_item(&mut self, i: Item) -> Option<Item> { - match i.inner { - clean::StrippedItem(..) => { - // We need to recurse into stripped modules to strip things - // like impl methods but when doing so we must not add any - // items to the `retained` set. - debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name); - let old = mem::replace(&mut self.update_retained, false); - let ret = self.fold_item_recur(i); - self.update_retained = old; - return ret; - } - // These items can all get re-exported - clean::OpaqueTyItem(..) - | clean::TypedefItem(..) - | clean::StaticItem(..) - | clean::StructItem(..) - | clean::EnumItem(..) - | clean::TraitItem(..) - | clean::FunctionItem(..) - | clean::VariantItem(..) - | clean::MethodItem(..) - | clean::ForeignFunctionItem(..) - | clean::ForeignStaticItem(..) - | clean::ConstantItem(..) - | clean::UnionItem(..) - | clean::AssocConstItem(..) - | clean::TraitAliasItem(..) - | clean::ForeignTypeItem => { - if i.def_id.is_local() { - if !self.access_levels.is_exported(i.def_id) { - debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); - return None; - } - } - } - - clean::StructFieldItem(..) => { - if i.visibility != clean::Public { - return StripItem(i).strip(); - } - } - - clean::ModuleItem(..) => { - if i.def_id.is_local() && i.visibility != clean::Public { - debug!("Stripper: stripping module {:?}", i.name); - let old = mem::replace(&mut self.update_retained, false); - let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); - self.update_retained = old; - return ret; - } - } - - // handled in the `strip-priv-imports` pass - clean::ExternCrateItem(..) | clean::ImportItem(..) => {} - - clean::ImplItem(..) => {} - - // tymethods/macros have no control over privacy - clean::MacroItem(..) | clean::TyMethodItem(..) => {} - - // Proc-macros are always public - clean::ProcMacroItem(..) => {} - - // Primitives are never stripped - clean::PrimitiveItem(..) => {} - - // Associated types are never stripped - clean::AssocTypeItem(..) => {} - - // Keywords are never stripped - clean::KeywordItem(..) => {} - } - - let fastreturn = match i.inner { - // nothing left to do for traits (don't want to filter their - // methods out, visibility controlled by the trait) - clean::TraitItem(..) => true, - - // implementations of traits are always public. - clean::ImplItem(ref imp) if imp.trait_.is_some() => true, - // Struct variant fields have inherited visibility - clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true, - _ => false, - }; - - let i = if fastreturn { - if self.update_retained { - self.retained.insert(i.def_id); - } - return Some(i); - } else { - self.fold_item_recur(i) - }; - - if let Some(ref i) = i { - if self.update_retained { - self.retained.insert(i.def_id); - } - } - i - } -} - -// This stripper discards all impls which reference stripped items -struct ImplStripper<'a> { - retained: &'a DefIdSet, -} - -impl<'a> DocFolder for ImplStripper<'a> { - fn fold_item(&mut self, i: Item) -> Option<Item> { - if let clean::ImplItem(ref imp) = i.inner { - // emptied none trait impls can be stripped - if imp.trait_.is_none() && imp.items.is_empty() { - return None; - } - if let Some(did) = imp.for_.def_id() { - if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) { - debug!("ImplStripper: impl item for stripped type; removing"); - return None; - } - } - if let Some(did) = imp.trait_.def_id() { - if did.is_local() && !self.retained.contains(&did) { - debug!("ImplStripper: impl item for stripped trait; removing"); - return None; - } - } - if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) { - for typaram in generics { - if let Some(did) = typaram.def_id() { - if did.is_local() && !self.retained.contains(&did) { - debug!( - "ImplStripper: stripped item in trait's generics; removing impl" - ); - return None; - } - } - } - } - } - self.fold_item_recur(i) - } -} - -// This stripper discards all private import statements (`use`, `extern crate`) -struct ImportStripper; -impl DocFolder for ImportStripper { - fn fold_item(&mut self, i: Item) -> Option<Item> { - match i.inner { - clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => { - None - } - _ => self.fold_item_recur(i), - } - } -} - /// Returns a span encompassing all the given attributes. crate fn span_of_attrs(attrs: &clean::Attributes) -> Option<Span> { if attrs.doc_strings.is_empty() { diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs new file mode 100644 index 00000000000..9b4f62235f5 --- /dev/null +++ b/src/librustdoc/passes/stripper.rs @@ -0,0 +1,172 @@ +use rustc_hir::def_id::{DefId, DefIdSet}; +use rustc_middle::middle::privacy::AccessLevels; +use std::mem; + +use crate::clean::{self, GetDefId, Item}; +use crate::fold::{DocFolder, StripItem}; + +pub struct Stripper<'a> { + pub retained: &'a mut DefIdSet, + pub access_levels: &'a AccessLevels<DefId>, + pub update_retained: bool, +} + +impl<'a> DocFolder for Stripper<'a> { + fn fold_item(&mut self, i: Item) -> Option<Item> { + match i.inner { + clean::StrippedItem(..) => { + // We need to recurse into stripped modules to strip things + // like impl methods but when doing so we must not add any + // items to the `retained` set. + debug!("Stripper: recursing into stripped {:?} {:?}", i.type_(), i.name); + let old = mem::replace(&mut self.update_retained, false); + let ret = self.fold_item_recur(i); + self.update_retained = old; + return ret; + } + // These items can all get re-exported + clean::OpaqueTyItem(..) + | clean::TypedefItem(..) + | clean::StaticItem(..) + | clean::StructItem(..) + | clean::EnumItem(..) + | clean::TraitItem(..) + | clean::FunctionItem(..) + | clean::VariantItem(..) + | clean::MethodItem(..) + | clean::ForeignFunctionItem(..) + | clean::ForeignStaticItem(..) + | clean::ConstantItem(..) + | clean::UnionItem(..) + | clean::AssocConstItem(..) + | clean::TraitAliasItem(..) + | clean::ForeignTypeItem => { + if i.def_id.is_local() { + if !self.access_levels.is_exported(i.def_id) { + debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); + return None; + } + } + } + + clean::StructFieldItem(..) => { + if i.visibility != clean::Public { + return StripItem(i).strip(); + } + } + + clean::ModuleItem(..) => { + if i.def_id.is_local() && i.visibility != clean::Public { + debug!("Stripper: stripping module {:?}", i.name); + let old = mem::replace(&mut self.update_retained, false); + let ret = StripItem(self.fold_item_recur(i).unwrap()).strip(); + self.update_retained = old; + return ret; + } + } + + // handled in the `strip-priv-imports` pass + clean::ExternCrateItem(..) | clean::ImportItem(..) => {} + + clean::ImplItem(..) => {} + + // tymethods/macros have no control over privacy + clean::MacroItem(..) | clean::TyMethodItem(..) => {} + + // Proc-macros are always public + clean::ProcMacroItem(..) => {} + + // Primitives are never stripped + clean::PrimitiveItem(..) => {} + + // Associated types are never stripped + clean::AssocTypeItem(..) => {} + + // Keywords are never stripped + clean::KeywordItem(..) => {} + } + + let fastreturn = match i.inner { + // nothing left to do for traits (don't want to filter their + // methods out, visibility controlled by the trait) + clean::TraitItem(..) => true, + + // implementations of traits are always public. + clean::ImplItem(ref imp) if imp.trait_.is_some() => true, + // Struct variant fields have inherited visibility + clean::VariantItem(clean::Variant { kind: clean::VariantKind::Struct(..) }) => true, + _ => false, + }; + + let i = if fastreturn { + if self.update_retained { + self.retained.insert(i.def_id); + } + return Some(i); + } else { + self.fold_item_recur(i) + }; + + if let Some(ref i) = i { + if self.update_retained { + self.retained.insert(i.def_id); + } + } + i + } +} + +/// This stripper discards all impls which reference stripped items +pub struct ImplStripper<'a> { + pub retained: &'a DefIdSet, +} + +impl<'a> DocFolder for ImplStripper<'a> { + fn fold_item(&mut self, i: Item) -> Option<Item> { + if let clean::ImplItem(ref imp) = i.inner { + // emptied none trait impls can be stripped + if imp.trait_.is_none() && imp.items.is_empty() { + return None; + } + if let Some(did) = imp.for_.def_id() { + if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did) { + debug!("ImplStripper: impl item for stripped type; removing"); + return None; + } + } + if let Some(did) = imp.trait_.def_id() { + if did.is_local() && !self.retained.contains(&did) { + debug!("ImplStripper: impl item for stripped trait; removing"); + return None; + } + } + if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) { + for typaram in generics { + if let Some(did) = typaram.def_id() { + if did.is_local() && !self.retained.contains(&did) { + debug!( + "ImplStripper: stripped item in trait's generics; removing impl" + ); + return None; + } + } + } + } + } + self.fold_item_recur(i) + } +} + +/// This stripper discards all private import statements (`use`, `extern crate`) +pub struct ImportStripper; + +impl DocFolder for ImportStripper { + fn fold_item(&mut self, i: Item) -> Option<Item> { + match i.inner { + clean::ExternCrateItem(..) | clean::ImportItem(..) if i.visibility != clean::Public => { + None + } + _ => self.fold_item_recur(i), + } + } +} diff --git a/src/llvm-project b/src/llvm-project -Subproject 3adf16e0cb1a0d9d7216883ac47857a6d1ee658 +Subproject 3c5d47c81d78e9316e971c9870e8bc7c2c449d2 diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs index b195ed88c72..04e840dc166 100644 --- a/src/test/assembly/asm/mips-types.rs +++ b/src/test/assembly/asm/mips-types.rs @@ -1,6 +1,8 @@ // no-system-llvm +// revisions: mips32 mips64 // assembly-output: emit-asm -// compile-flags: --target mips-unknown-linux-gnu +//[mips32] compile-flags: --target mips-unknown-linux-gnu +//[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 // needs-llvm-components: mips #![feature(no_core, lang_items, rustc_attrs, repr_simd)] @@ -32,7 +34,9 @@ impl Copy for i8 {} impl Copy for u8 {} impl Copy for i16 {} impl Copy for i32 {} +impl Copy for i64 {} impl Copy for f32 {} +impl Copy for f64 {} impl Copy for ptr {} extern "C" { fn extern_func(); @@ -44,148 +48,190 @@ extern "Rust" { fn dont_merge(s: &str); } -macro_rules! check { ($func:ident, $ty:ty, $class:ident) => { +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { dont_merge(stringify!($func)); let y; - asm!("move {}, {}", out($class) y, in($class) x); + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); y } };} -macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt) => { +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { #[no_mangle] pub unsafe fn $func(x: $ty) -> $ty { dont_merge(stringify!($func)); let y; - asm!(concat!("move ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); y } };} -// CHECK-LABEL: sym_static: -// CHECK: #APP -// CHECK: lw $3, %got(extern_static) -// CHECK: #NO_APP +// mips32-LABEL: sym_static_32: +// mips32: #APP +// mips32: lw $3, %got(extern_static) +// mips32: #NO_APP +#[cfg(mips32)] #[no_mangle] -pub unsafe fn sym_static() { - dont_merge(stringify!($func)); +pub unsafe fn sym_static_32() { + asm!("lw $v1, {}", sym extern_static); +} - asm!("la $v1, {}", sym extern_static); +// mips32-LABEL: sym_fn_32: +// mips32: #APP +// mips32: lw $3, %got(extern_func) +// mips32: #NO_APP +#[cfg(mips32)] +#[no_mangle] +pub unsafe fn sym_fn_32() { + asm!("lw $v1, {}", sym extern_func); } -// CHECK-LABEL: sym_fn: -// CHECK: #APP -// CHECK: lw $3, %got(extern_func) -// CHECK: #NO_APP +// mips64-LABEL: sym_static_64: +// mips64: #APP +// mips64: ld $3, %got_disp(extern_static) +// mips64: #NO_APP +#[cfg(mips64)] #[no_mangle] -pub unsafe fn sym_fn() { - dont_merge(stringify!($func)); +pub unsafe fn sym_static_64() { + asm!("ld $v1, {}", sym extern_static); +} - asm!("la $v1, {}", sym extern_func); +// mips64-LABEL: sym_fn_64: +// mips64: #APP +// mips64: ld $3, %got_disp(extern_func) +// mips64: #NO_APP +#[cfg(mips64)] +#[no_mangle] +pub unsafe fn sym_fn_64() { + asm!("ld $v1, {}", sym extern_func); } // CHECK-LABEL: reg_f32: // CHECK: #APP // CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}} // CHECK: #NO_APP -#[no_mangle] -pub unsafe fn reg_f32(x: f32) -> f32 { - dont_merge("reg_f32"); - let y; - asm!("mov.s {}, {}", out(freg) y, in(freg) x); - y -} +check!(reg_f32, f32, freg, "mov.s"); // CHECK-LABEL: f0_f32: // CHECK: #APP // CHECK: mov.s $f0, $f0 // CHECK: #NO_APP #[no_mangle] -pub unsafe fn f0_f32(x: f32) -> f32 { - dont_merge("f0_f32"); - let y; - asm!("mov.s $f0, $f0", lateout("$f0") y, in("$f0") x); - y -} +check_reg!(f0_f32, f32, "$f0", "mov.s"); + +// CHECK-LABEL: reg_f32_64: +// CHECK: #APP +// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32_64, f32, freg, "mov.d"); + +// CHECK-LABEL: f0_f32_64: +// CHECK: #APP +// CHECK: mov.d $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +check_reg!(f0_f32_64, f32, "$f0", "mov.d"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +#[no_mangle] +check!(reg_f64, f64, freg, "mov.d"); + +// CHECK-LABEL: f0_f64: +// CHECK: #APP +// CHECK: mov.d $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +check_reg!(f0_f64, f64, "$f0", "mov.d"); // CHECK-LABEL: reg_ptr: // CHECK: #APP // CHECK: move ${{[0-9]+}}, ${{[0-9]+}} // CHECK: #NO_APP -check!(reg_ptr, ptr, reg); +check!(reg_ptr, ptr, reg, "move"); // CHECK-LABEL: reg_i32: // CHECK: #APP // CHECK: move ${{[0-9]+}}, ${{[0-9]+}} // CHECK: #NO_APP -check!(reg_i32, i32, reg); +check!(reg_i32, i32, reg, "move"); // CHECK-LABEL: reg_f32_soft: // CHECK: #APP // CHECK: move ${{[0-9]+}}, ${{[0-9]+}} // CHECK: #NO_APP -check!(reg_f32_soft, f32, reg); +check!(reg_f32_soft, f32, reg, "move"); + +// mips64-LABEL: reg_f64_soft: +// mips64: #APP +// mips64: move ${{[0-9]+}}, ${{[0-9]+}} +// mips64: #NO_APP +#[cfg(mips64)] +check!(reg_f64_soft, f64, reg, "move"); // CHECK-LABEL: reg_i8: // CHECK: #APP // CHECK: move ${{[0-9]+}}, ${{[0-9]+}} // CHECK: #NO_APP -check!(reg_i8, i8, reg); +check!(reg_i8, i8, reg, "move"); // CHECK-LABEL: reg_u8: // CHECK: #APP // CHECK: move ${{[0-9]+}}, ${{[0-9]+}} // CHECK: #NO_APP -check!(reg_u8, u8, reg); +check!(reg_u8, u8, reg, "move"); // CHECK-LABEL: reg_i16: // CHECK: #APP // CHECK: move ${{[0-9]+}}, ${{[0-9]+}} // CHECK: #NO_APP -check!(reg_i16, i16, reg); +check!(reg_i16, i16, reg, "move"); -// CHECK-LABEL: t0_ptr: -// CHECK: #APP -// CHECK: move $8, $8 -// CHECK: #NO_APP -check_reg!(t0_ptr, ptr, "$t0"); +// mips64-LABEL: reg_i64: +// mips64: #APP +// mips64: move ${{[0-9]+}}, ${{[0-9]+}} +// mips64: #NO_APP +#[cfg(mips64)] +check!(reg_i64, i64, reg, "move"); -// CHECK-LABEL: t0_i32: +// CHECK-LABEL: r8_ptr: // CHECK: #APP // CHECK: move $8, $8 // CHECK: #NO_APP -check_reg!(t0_i32, i32, "$t0"); +check_reg!(r8_ptr, ptr, "$8", "move"); -// CHECK-LABEL: t0_f32: +// CHECK-LABEL: r8_i32: // CHECK: #APP // CHECK: move $8, $8 // CHECK: #NO_APP -check_reg!(t0_f32, f32, "$t0"); +check_reg!(r8_i32, i32, "$8", "move"); -// CHECK-LABEL: t0_i8: +// CHECK-LABEL: r8_f32: // CHECK: #APP // CHECK: move $8, $8 // CHECK: #NO_APP -check_reg!(t0_i8, i8, "$t0"); +check_reg!(r8_f32, f32, "$8", "move"); -// CHECK-LABEL: t0_u8: +// CHECK-LABEL: r8_i8: // CHECK: #APP // CHECK: move $8, $8 // CHECK: #NO_APP -check_reg!(t0_u8, u8, "$t0"); +check_reg!(r8_i8, i8, "$8", "move"); -// CHECK-LABEL: t0_i16: +// CHECK-LABEL: r8_u8: // CHECK: #APP // CHECK: move $8, $8 // CHECK: #NO_APP -check_reg!(t0_i16, i16, "$t0"); +check_reg!(r8_u8, u8, "$8", "move"); // CHECK-LABEL: r8_i16: // CHECK: #APP // CHECK: move $8, $8 // CHECK: #NO_APP -check_reg!(r8_i16, i16, "$8"); +check_reg!(r8_i16, i16, "$8", "move"); diff --git a/src/test/codegen/len-is-bounded.rs b/src/test/codegen/len-is-bounded.rs deleted file mode 100644 index bb74fc3b275..00000000000 --- a/src/test/codegen/len-is-bounded.rs +++ /dev/null @@ -1,24 +0,0 @@ -// min-llvm-version: 11.0 -// compile-flags: -O -C panic=abort -#![crate_type = "lib"] - -#[no_mangle] -pub fn len_range(a: &[u8], b: &[u8]) -> usize { - // CHECK-NOT: panic - a.len().checked_add(b.len()).unwrap() -} - -#[no_mangle] -pub fn len_range_on_non_byte(a: &[u16], b: &[u16]) -> usize { - // CHECK-NOT: panic - a.len().checked_add(b.len()).unwrap() -} - -pub struct Zst; - -#[no_mangle] -pub fn zst_range(a: &[Zst], b: &[Zst]) -> usize { - // Zsts may be arbitrarily large. - // CHECK: panic - a.len().checked_add(b.len()).unwrap() -} diff --git a/src/test/codegen/loop.rs b/src/test/codegen/loop.rs new file mode 100644 index 00000000000..e54298eed05 --- /dev/null +++ b/src/test/codegen/loop.rs @@ -0,0 +1,15 @@ +// compile-flags: -C opt-level=3 + +#![crate_type = "lib"] + +// CHECK-LABEL: @check_loop +#[no_mangle] +pub fn check_loop() -> u8 { + // CHECK-NOT: unreachable + call_looper() +} + +#[no_mangle] +fn call_looper() -> ! { + loop {} +} diff --git a/src/test/codegen/tune-cpu-on-functions.rs b/src/test/codegen/tune-cpu-on-functions.rs new file mode 100644 index 00000000000..9121799cdbf --- /dev/null +++ b/src/test/codegen/tune-cpu-on-functions.rs @@ -0,0 +1,21 @@ +// This test makes sure that functions get annotated with the proper +// "tune-cpu" attribute in LLVM. + +// no-prefer-dynamic +// ignore-tidy-linelength +// compile-flags: -C no-prepopulate-passes -C panic=abort -C linker-plugin-lto -Cpasses=name-anon-globals -Z tune-cpu=generic + +#![crate_type = "staticlib"] + +// CHECK-LABEL: define {{.*}} @exported() {{.*}} #0 +#[no_mangle] +pub extern fn exported() { + not_exported(); +} + +// CHECK-LABEL: ; tune_cpu_on_functions::not_exported +// CHECK-NEXT: ; Function Attrs: +// CHECK-NEXT: define {{.*}}() {{.*}} #0 +fn not_exported() {} + +// CHECK: attributes #0 = {{.*}} "tune-cpu"="{{.*}}" diff --git a/src/test/debuginfo/pretty-std-collections.rs b/src/test/debuginfo/pretty-std-collections.rs index a4fbff5725c..c6d2090759f 100644 --- a/src/test/debuginfo/pretty-std-collections.rs +++ b/src/test/debuginfo/pretty-std-collections.rs @@ -34,17 +34,20 @@ // gdb-check:$6 = BTreeMap(size=15) = {[0] = pretty_std_collections::MyLeafNode (0), [...]} // (abbreviated because it's boring but we need enough elements to include internal nodes) +// gdb-command: print zst_btree_map +// gdb-check:$7 = BTreeMap(size=1) + // gdb-command: print vec_deque -// gdb-check:$7 = VecDeque(size=3) = {5, 3, 7} +// gdb-check:$8 = VecDeque(size=3) = {5, 3, 7} // gdb-command: print vec_deque2 -// gdb-check:$8 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8} +// gdb-check:$9 = VecDeque(size=7) = {2, 3, 4, 5, 6, 7, 8} // gdb-command: print hash_map -// gdb-check:$9 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40} +// gdb-check:$10 = HashMap(size=4) = {[1] = 10, [2] = 20, [3] = 30, [4] = 40} // gdb-command: print hash_set -// gdb-check:$10 = HashSet(size=4) = {1, 2, 3, 4} +// gdb-check:$11 = HashSet(size=4) = {1, 2, 3, 4} // === LLDB TESTS ================================================================================== @@ -69,9 +72,9 @@ #![allow(unused_variables)] use std::collections::BTreeMap; use std::collections::BTreeSet; -use std::collections::VecDeque; use std::collections::HashMap; use std::collections::HashSet; +use std::collections::VecDeque; use std::hash::{BuildHasherDefault, Hasher}; struct MyLeafNode(i32); // helps to ensure we don't blindly replace substring "LeafNode" @@ -111,6 +114,9 @@ fn main() { nasty_btree_map.insert(i, MyLeafNode(i)); } + let mut zst_btree_map: BTreeMap<(), ()> = BTreeMap::new(); + zst_btree_map.insert((), ()); + // VecDeque let mut vec_deque = VecDeque::new(); vec_deque.push_back(5); diff --git a/src/test/incremental/thinlto/cgu_invalidated_via_import.rs b/src/test/incremental/thinlto/cgu_invalidated_via_import.rs index 8160f8f3a99..5fe435d796f 100644 --- a/src/test/incremental/thinlto/cgu_invalidated_via_import.rs +++ b/src/test/incremental/thinlto/cgu_invalidated_via_import.rs @@ -33,7 +33,9 @@ mod foo { #[cfg(not(cfail1))] pub fn inlined_fn() -> u32 { - 1234 + // See `cgu_keeps_identical_fn.rs` for why this is different + // from the other version of this function. + 12345 } } diff --git a/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs b/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs new file mode 100644 index 00000000000..0fd5abee118 --- /dev/null +++ b/src/test/incremental/thinlto/cgu_keeps_identical_fn.rs @@ -0,0 +1,47 @@ +// This test is almost identical to `cgu_invalided_via_import`, except that +// the two versions of `inline_fn` are identical. Neither version of `inlined_fn` +// ends up with any spans in its LLVM bitecode, so LLVM is able to skip +// re-building any modules which import 'inlined_fn' + +// revisions: cfail1 cfail2 cfail3 +// compile-flags: -Z query-dep-graph -O +// build-pass (FIXME(62277): could be check-pass?) + +#![feature(rustc_attrs)] +#![crate_type="rlib"] + +#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo", + cfg="cfail2", + kind="no")] +#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-foo", + cfg="cfail3", + kind="post-lto")] + +#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar", + cfg="cfail2", + kind="post-lto")] +#![rustc_expected_cgu_reuse(module="cgu_keeps_identical_fn-bar", + cfg="cfail3", + kind="post-lto")] + +mod foo { + + // Trivial functions like this one are imported very reliably by ThinLTO. + #[cfg(cfail1)] + pub fn inlined_fn() -> u32 { + 1234 + } + + #[cfg(not(cfail1))] + pub fn inlined_fn() -> u32 { + 1234 + } +} + +pub mod bar { + use foo::inlined_fn; + + pub fn caller() -> u32 { + inlined_fn() + } +} diff --git a/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs b/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs index 24e5d2438bd..045f2011958 100644 --- a/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs +++ b/src/test/incremental/thinlto/independent_cgus_dont_affect_each_other.rs @@ -37,7 +37,9 @@ mod foo { #[cfg(not(cfail1))] pub fn inlined_fn() -> u32 { - 1234 + // See `cgu_keeps_identical_fn.rs` for why this is different + // from the other version of this function. + 12345 } } diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir index d9c6b4f0029..0d5760b4cd5 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir +++ b/src/test/mir-opt/const_promotion_extern_static.FOO-promoted[0].ConstProp.after.mir @@ -5,8 +5,6 @@ promoted[0] in FOO: &[&i32; 1] = { let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:32: 13:45 let mut _3: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 - scope 1 { - } bb0: { _3 = const {alloc2: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:13:42: 13:43 diff --git a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs index dd49ca67c67..0e1bef6f68d 100644 --- a/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs +++ b/src/test/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs @@ -3,7 +3,6 @@ extern crate rustc_codegen_ssa; extern crate rustc_errors; extern crate rustc_middle; -#[macro_use] extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_hir; @@ -12,17 +11,19 @@ extern crate rustc_span; extern crate rustc_symbol_mangling; extern crate rustc_target; +use rustc_codegen_ssa::back::linker::LinkerInfo; use rustc_codegen_ssa::traits::CodegenBackend; -use rustc_data_structures::owning_ref::OwningRef; +use rustc_codegen_ssa::{CodegenResults, CrateInfo}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::MetadataRef; use rustc_errors::ErrorReported; use rustc_middle::dep_graph::DepGraph; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::cstore::{EncodedMetadata, MetadataLoader, MetadataLoaderDyn}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::OutputFilenames; use rustc_session::Session; -use rustc_span::symbol::Symbol; use rustc_target::spec::Target; use std::any::Any; use std::path::Path; @@ -31,14 +32,11 @@ pub struct NoLlvmMetadataLoader; impl MetadataLoader for NoLlvmMetadataLoader { fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result<MetadataRef, String> { - let buf = - std::fs::read(filename).map_err(|e| format!("metadata file open err: {:?}", e))?; - let buf: OwningRef<Vec<u8>, [u8]> = OwningRef::new(buf); - Ok(rustc_erase_owner!(buf.map_owner_box())) + unreachable!("some_crate.rs shouldn't depend on any external crates"); } fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String> { - self.get_rlib_metadata(target, filename) + unreachable!("some_crate.rs shouldn't depend on any external crates"); } } @@ -49,53 +47,49 @@ impl CodegenBackend for TheBackend { Box::new(NoLlvmMetadataLoader) } - fn provide(&self, providers: &mut Providers) { - rustc_symbol_mangling::provide(providers); - - providers.supported_target_features = |tcx, _cnum| { - Default::default() // Just a dummy - }; - providers.is_reachable_non_generic = |_tcx, _defid| true; - providers.exported_symbols = |_tcx, _crate| &[]; - } - - fn provide_extern(&self, providers: &mut Providers) { - providers.is_reachable_non_generic = |_tcx, _defid| true; - } + fn provide(&self, providers: &mut Providers) {} + fn provide_extern(&self, providers: &mut Providers) {} fn codegen_crate<'a, 'tcx>( &self, tcx: TyCtxt<'tcx>, - _metadata: EncodedMetadata, + metadata: EncodedMetadata, _need_metadata_module: bool, ) -> Box<dyn Any> { use rustc_hir::def_id::LOCAL_CRATE; - Box::new(tcx.crate_name(LOCAL_CRATE) as Symbol) + Box::new(CodegenResults { + crate_name: tcx.crate_name(LOCAL_CRATE), + modules: vec![], + allocator_module: None, + metadata_module: None, + metadata, + windows_subsystem: None, + linker_info: LinkerInfo::new(tcx), + crate_info: CrateInfo::new(tcx), + }) } fn join_codegen( &self, ongoing_codegen: Box<dyn Any>, _sess: &Session, - _dep_graph: &DepGraph, - ) -> Result<Box<dyn Any>, ErrorReported> { - let crate_name = ongoing_codegen - .downcast::<Symbol>() - .expect("in join_codegen: ongoing_codegen is not a Symbol"); - Ok(crate_name) + ) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> { + let codegen_results = ongoing_codegen + .downcast::<CodegenResults>() + .expect("in join_codegen: ongoing_codegen is not a CodegenResults"); + Ok((*codegen_results, FxHashMap::default())) } fn link( &self, sess: &Session, - codegen_results: Box<dyn Any>, + codegen_results: CodegenResults, outputs: &OutputFilenames, ) -> Result<(), ErrorReported> { use rustc_session::{config::CrateType, output::out_filename}; use std::io::Write; - let crate_name = - codegen_results.downcast::<Symbol>().expect("in link: codegen_results is not a Symbol"); + let crate_name = codegen_results.crate_name; for &crate_type in sess.opts.crate_types.iter() { if crate_type != CrateType::Rlib { sess.fatal(&format!("Crate type is {:?}", crate_type)); diff --git a/src/test/rustdoc-js/doc-alias-whitespace.js b/src/test/rustdoc-js/doc-alias-whitespace.js new file mode 100644 index 00000000000..c9fc0c4311f --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-whitespace.js @@ -0,0 +1,19 @@ +// exact-check + +const QUERY = [ + 'Demon Lord', +]; + +const EXPECTED = [ + { + 'others': [ + { + 'path': 'doc_alias_whitespace', + 'name': 'Struct', + 'alias': 'Demon Lord', + 'href': '../doc_alias_whitespace/struct.Struct.html', + 'is_alias': true + }, + ], + }, +]; diff --git a/src/test/rustdoc-js/doc-alias-whitespace.rs b/src/test/rustdoc-js/doc-alias-whitespace.rs new file mode 100644 index 00000000000..bea3e382ae4 --- /dev/null +++ b/src/test/rustdoc-js/doc-alias-whitespace.rs @@ -0,0 +1,4 @@ +#![feature(doc_alias)] + +#[doc(alias = "Demon Lord")] +pub struct Struct; diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs index c8bec39fad6..0ca2349a43b 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.rs +++ b/src/test/rustdoc-ui/check-doc-alias-attr.rs @@ -11,6 +11,7 @@ pub struct Bar; #[doc(alias = "\n")] //~ ERROR #[doc(alias = " ")] //~^ ERROR -#[doc(alias = " ")] //~ ERROR #[doc(alias = "\t")] //~ ERROR +#[doc(alias = " hello")] //~ ERROR +#[doc(alias = "hello ")] //~ ERROR pub struct Foo; diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr index be7d7b3dbea..2c417a3bb65 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr @@ -36,17 +36,23 @@ LL | #[doc(alias = " LL | | ")] | |_^ -error: ' ' character isn't allowed in `#[doc(alias = "...")]` +error: '\t' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:14:7 | -LL | #[doc(alias = " ")] - | ^^^^^^^^^^^ +LL | #[doc(alias = "\t")] + | ^^^^^^^^^^^^ -error: '\t' character isn't allowed in `#[doc(alias = "...")]` +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:15:7 | -LL | #[doc(alias = "\t")] - | ^^^^^^^^^^^^ +LL | #[doc(alias = " hello")] + | ^^^^^^^^^^^^^^^^ + +error: `#[doc(alias = "...")]` cannot start or end with ' ' + --> $DIR/check-doc-alias-attr.rs:16:7 + | +LL | #[doc(alias = "hello ")] + | ^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.rs b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs new file mode 100644 index 00000000000..c077be31b20 --- /dev/null +++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.rs @@ -0,0 +1,41 @@ +// compile-flags:-Z unstable-options --show-coverage +// check-pass + +//! Make sure to have some docs on your crate root + +#[allow(missing_docs)] +pub mod mod_foo { + pub struct Bar; +} + +/// This is a struct with a `#[allow(missing_docs)]` +pub struct AllowTheMissingDocs { + #[allow(missing_docs)] + pub empty_str: String, + + /// This has + #[allow(missing_docs)] + /// but also has documentation comments + pub hello: usize, + + /// The doc id just to create a boilerplate comment + pub doc_id: Vec<u8>, +} + +/// A function that has a documentation +pub fn this_is_func() {} + +#[allow(missing_docs)] +pub struct DemoStruct { + something: usize, +} + +#[allow(missing_docs)] +pub mod bar { + #[warn(missing_docs)] + pub struct Bar { //~ WARN + pub f: u32, //~ WARN + } + + pub struct NeedsNoDocs; +} diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr new file mode 100644 index 00000000000..3d5b512d14d --- /dev/null +++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stderr @@ -0,0 +1,20 @@ +warning: missing documentation for a struct + --> $DIR/allow_missing_docs.rs:36:5 + | +LL | pub struct Bar { + | ^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/allow_missing_docs.rs:35:12 + | +LL | #[warn(missing_docs)] + | ^^^^^^^^^^^^ + +warning: missing documentation for a struct field + --> $DIR/allow_missing_docs.rs:37:9 + | +LL | pub f: u32, + | ^^^^^^^^^^ + +warning: 2 warnings emitted + diff --git a/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout new file mode 100644 index 00000000000..17e8ee9e23d --- /dev/null +++ b/src/test/rustdoc-ui/coverage/allow_missing_docs.stdout @@ -0,0 +1,7 @@ ++-------------------------------------+------------+------------+------------+------------+ +| File | Documented | Percentage | Examples | Percentage | ++-------------------------------------+------------+------------+------------+------------+ +| ...i/coverage/allow_missing_docs.rs | 5 | 71.4% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ +| Total | 5 | 71.4% | 0 | 0.0% | ++-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs index ef928ae02f3..81e42643ae8 100644 --- a/src/test/rustdoc-ui/intra-link-errors.rs +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -2,7 +2,7 @@ //~^ NOTE lint level is defined // FIXME: this should say that it was skipped (maybe an allowed by default lint?) -/// [<invalid syntax>] +/// [invalid intra-doc syntax!!] /// [path::to::nonexistent::module] //~^ ERROR unresolved link diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.rs b/src/test/rustdoc-ui/intra-link-malformed-generics.rs new file mode 100644 index 00000000000..9c54092146f --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-malformed-generics.rs @@ -0,0 +1,19 @@ +#![deny(broken_intra_doc_links)] + +//! [Vec<] //~ ERROR +//! [Vec<Box<T] //~ ERROR +//! [Vec<Box<T>] //~ ERROR +//! [Vec<Box<T>>>] //~ ERROR +//! [Vec<T>>>] //~ ERROR +//! [<Vec] //~ ERROR +//! [Vec::<] //~ ERROR +//! [<T>] //~ ERROR +//! [<invalid syntax>] //~ ERROR +//! [Vec:<T>:new()] //~ ERROR +//! [Vec<<T>>] //~ ERROR +//! [Vec<>] //~ ERROR +//! [Vec<<>>] //~ ERROR + +// FIXME(#74563) support UFCS +//! [<Vec as IntoIterator>::into_iter] //~ ERROR +//! [<Vec<T> as IntoIterator>::iter] //~ ERROR diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.stderr b/src/test/rustdoc-ui/intra-link-malformed-generics.stderr new file mode 100644 index 00000000000..fe5d4cd1bbf --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-malformed-generics.stderr @@ -0,0 +1,102 @@ +error: unresolved link to `Vec<` + --> $DIR/intra-link-malformed-generics.rs:3:6 + | +LL | //! [Vec<] + | ^^^^ unbalanced angle brackets + | +note: the lint level is defined here + --> $DIR/intra-link-malformed-generics.rs:1:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `Vec<Box<T` + --> $DIR/intra-link-malformed-generics.rs:4:6 + | +LL | //! [Vec<Box<T] + | ^^^^^^^^^ unbalanced angle brackets + +error: unresolved link to `Vec<Box<T>` + --> $DIR/intra-link-malformed-generics.rs:5:6 + | +LL | //! [Vec<Box<T>] + | ^^^^^^^^^^ unbalanced angle brackets + +error: unresolved link to `Vec<Box<T>>>` + --> $DIR/intra-link-malformed-generics.rs:6:6 + | +LL | //! [Vec<Box<T>>>] + | ^^^^^^^^^^^^ unbalanced angle brackets + +error: unresolved link to `Vec<T>>>` + --> $DIR/intra-link-malformed-generics.rs:7:6 + | +LL | //! [Vec<T>>>] + | ^^^^^^^^ unbalanced angle brackets + +error: unresolved link to `<Vec` + --> $DIR/intra-link-malformed-generics.rs:8:6 + | +LL | //! [<Vec] + | ^^^^ unbalanced angle brackets + +error: unresolved link to `Vec::<` + --> $DIR/intra-link-malformed-generics.rs:9:6 + | +LL | //! [Vec::<] + | ^^^^^^ unbalanced angle brackets + +error: unresolved link to `<T>` + --> $DIR/intra-link-malformed-generics.rs:10:6 + | +LL | //! [<T>] + | ^^^ missing type for generic parameters + +error: unresolved link to `<invalid syntax>` + --> $DIR/intra-link-malformed-generics.rs:11:6 + | +LL | //! [<invalid syntax>] + | ^^^^^^^^^^^^^^^^ missing type for generic parameters + +error: unresolved link to `Vec:<T>:new` + --> $DIR/intra-link-malformed-generics.rs:12:6 + | +LL | //! [Vec:<T>:new()] + | ^^^^^^^^^^^^^ has invalid path separator + +error: unresolved link to `Vec<<T>>` + --> $DIR/intra-link-malformed-generics.rs:13:6 + | +LL | //! [Vec<<T>>] + | ^^^^^^^^ too many angle brackets + +error: unresolved link to `Vec<>` + --> $DIR/intra-link-malformed-generics.rs:14:6 + | +LL | //! [Vec<>] + | ^^^^^ empty angle brackets + +error: unresolved link to `Vec<<>>` + --> $DIR/intra-link-malformed-generics.rs:15:6 + | +LL | //! [Vec<<>>] + | ^^^^^^^ too many angle brackets + +error: unresolved link to `<Vec as IntoIterator>::into_iter` + --> $DIR/intra-link-malformed-generics.rs:18:6 + | +LL | //! [<Vec as IntoIterator>::into_iter] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported + | + = note: see https://github.com/rust-lang/rust/issues/74563 for more information + +error: unresolved link to `<Vec<T> as IntoIterator>::iter` + --> $DIR/intra-link-malformed-generics.rs:19:6 + | +LL | //! [<Vec<T> as IntoIterator>::iter] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported + | + = note: see https://github.com/rust-lang/rust/issues/74563 for more information + +error: aborting due to 15 previous errors + diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.rs b/src/test/rustdoc-ui/intra-links-ambiguity.rs index d1597cdca66..f63435337cf 100644 --- a/src/test/rustdoc-ui/intra-links-ambiguity.rs +++ b/src/test/rustdoc-ui/intra-links-ambiguity.rs @@ -34,3 +34,7 @@ pub mod foo { /// /// Ambiguous non-implied shortcut link [`foo::bar`]. //~ERROR `foo::bar` pub struct Docs {} + +/// [true] //~ ERROR `true` is both a module and a builtin type +/// [primitive@true] +pub mod r#true {} diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr index 17891ca05ef..21b92a96737 100644 --- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -82,5 +82,20 @@ help: to link to the function, add parentheses LL | /// Ambiguous non-implied shortcut link [`foo::bar()`]. | ^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: `true` is both a module and a builtin type + --> $DIR/intra-links-ambiguity.rs:38:6 + | +LL | /// [true] + | ^^^^ ambiguous link + | +help: to link to the module, prefix with `mod@` + | +LL | /// [mod@true] + | ^^^^^^^^ +help: to link to the builtin type, prefix with `prim@` + | +LL | /// [prim@true] + | ^^^^^^^^^ + +error: aborting due to 6 previous errors diff --git a/src/test/rustdoc-ui/invalid-html-tags.rs b/src/test/rustdoc-ui/invalid-html-tags.rs index d878e390ca3..56ca7e79d43 100644 --- a/src/test/rustdoc-ui/invalid-html-tags.rs +++ b/src/test/rustdoc-ui/invalid-html-tags.rs @@ -73,3 +73,17 @@ pub fn e() {} /// <div></div //~^ ERROR unclosed HTML tag `div` pub fn f() {} + +/// <!----> +/// <!-- --> +/// <!-- <div> --> +/// <!-- <!-- --> +pub fn g() {} + +/// <!-- +/// --> +pub fn h() {} + +/// <!-- +//~^ ERROR Unclosed HTML comment +pub fn i() {} diff --git a/src/test/rustdoc-ui/invalid-html-tags.stderr b/src/test/rustdoc-ui/invalid-html-tags.stderr index 11f176ff05c..aa9ace006bd 100644 --- a/src/test/rustdoc-ui/invalid-html-tags.stderr +++ b/src/test/rustdoc-ui/invalid-html-tags.stderr @@ -76,5 +76,11 @@ error: unclosed HTML tag `div` LL | /// <div></div | ^^^^^ -error: aborting due to 12 previous errors +error: Unclosed HTML comment + --> $DIR/invalid-html-tags.rs:87:5 + | +LL | /// <!-- + | ^^^ + +error: aborting due to 13 previous errors diff --git a/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs new file mode 100644 index 00000000000..fc51995a94e --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs @@ -0,0 +1,6 @@ +#![crate_name = "inner"] + +/// Links to [f()] +pub struct Inner; + +pub fn f() {} diff --git a/src/test/rustdoc/auxiliary/reexport-check.rs b/src/test/rustdoc/auxiliary/reexport-check.rs new file mode 100644 index 00000000000..672ccb1cf0e --- /dev/null +++ b/src/test/rustdoc/auxiliary/reexport-check.rs @@ -0,0 +1,2 @@ +/// Docs in original +pub struct S; diff --git a/src/test/rustdoc/doc-cfg-simplification.rs b/src/test/rustdoc/doc-cfg-simplification.rs new file mode 100644 index 00000000000..633df661be0 --- /dev/null +++ b/src/test/rustdoc/doc-cfg-simplification.rs @@ -0,0 +1,182 @@ +#![crate_name = "globuliferous"] +#![feature(doc_cfg)] + +// @has 'globuliferous/index.html' +// @count - '//*[@class="stab portability"]' 1 +// @matches - '//*[@class="stab portability"]' '^ratel$' + +// @has 'globuliferous/ratel/index.html' +// @count - '//*[@class="stab portability"]' 8 +// @matches - '//*[@class="stab portability"]' 'crate feature ratel' +// @matches - '//*[@class="stab portability"]' '^zoonosology$' +// @matches - '//*[@class="stab portability"]' '^yusho$' +// @matches - '//*[@class="stab portability"]' '^nunciative$' +// @matches - '//*[@class="stab portability"]' '^thionic$' +// @matches - '//*[@class="stab portability"]' '^zincic$' +// @matches - '//*[@class="stab portability"]' '^cosmotellurian$' +// @matches - '//*[@class="stab portability"]' '^aposiopesis$' +#[doc(cfg(feature = "ratel"))] +pub mod ratel { + // @has 'globuliferous/ratel/fn.ovicide.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub fn ovicide() {} + + // @has 'globuliferous/ratel/fn.zoonosology.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and zoonosology' + #[doc(cfg(feature = "zoonosology"))] + pub fn zoonosology() {} + + // @has 'globuliferous/ratel/constant.DIAGRAPHICS.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub const DIAGRAPHICS: () = (); + + // @has 'globuliferous/ratel/constant.YUSHO.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and yusho' + #[doc(cfg(feature = "yusho"))] + pub const YUSHO: () = (); + + // @has 'globuliferous/ratel/static.KEYBUGLE.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub static KEYBUGLE: () = (); + + // @has 'globuliferous/ratel/static.NUNCIATIVE.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and nunciative' + #[doc(cfg(feature = "nunciative"))] + pub static NUNCIATIVE: () = (); + + // @has 'globuliferous/ratel/type.Wrick.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub type Wrick = (); + + // @has 'globuliferous/ratel/type.Thionic.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and thionic' + #[doc(cfg(feature = "thionic"))] + pub type Thionic = (); + + // @has 'globuliferous/ratel/struct.Eventration.html' + // @count - '//*[@class="stab portability"]' 1 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + pub struct Eventration; + + // @has 'globuliferous/ratel/struct.Zincic.html' + // @count - '//*[@class="stab portability"]' 2 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and zincic' + // @matches - '//*[@class="stab portability"]' 'crate feature rutherford' + #[doc(cfg(feature = "zincic"))] + pub struct Zincic { + pub rectigrade: (), + + #[doc(cfg(feature = "rutherford"))] + pub rutherford: (), + } + + // @has 'globuliferous/ratel/enum.Cosmotellurian.html' + // @count - '//*[@class="stab portability"]' 10 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and cosmotellurian' + // @matches - '//*[@class="stab portability"]' 'crate feature biotaxy' + // @matches - '//*[@class="stab portability"]' 'crate feature xiphopagus' + // @matches - '//*[@class="stab portability"]' 'crate feature juxtapositive' + // @matches - '//*[@class="stab portability"]' 'crate feature fuero' + // @matches - '//*[@class="stab portability"]' 'crate feature palaeophile' + // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth' + // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and xanthocomic' + // @matches - '//*[@class="stab portability"]' 'crate feature broadcloth' + // @matches - '//*[@class="stab portability"]' 'crate features broadcloth and whosoever' + #[doc(cfg(feature = "cosmotellurian"))] + pub enum Cosmotellurian { + Groundsel { + jagger: (), + + #[doc(cfg(feature = "xiphopagus"))] + xiphopagus: (), + }, + + #[doc(cfg(feature = "biotaxy"))] + Biotaxy { + glossography: (), + + #[doc(cfg(feature = "juxtapositive"))] + juxtapositive: (), + }, + } + + impl Cosmotellurian { + pub fn uxoricide() {} + + #[doc(cfg(feature = "fuero"))] + pub fn fuero() {} + + pub const MAMELLE: () = (); + + #[doc(cfg(feature = "palaeophile"))] + pub const PALAEOPHILE: () = (); + } + + #[doc(cfg(feature = "broadcloth"))] + impl Cosmotellurian { + pub fn trabeculated() {} + + #[doc(cfg(feature = "xanthocomic"))] + pub fn xanthocomic() {} + + pub const BRACHIFEROUS: () = (); + + #[doc(cfg(feature = "whosoever"))] + pub const WHOSOEVER: () = (); + } + + // @has 'globuliferous/ratel/trait.Gnotobiology.html' + // @count - '//*[@class="stab portability"]' 4 + // @matches - '//*[@class="stab portability"]' 'crate feature ratel' + // @matches - '//*[@class="stab portability"]' 'crate feature unzymotic' + // @matches - '//*[@class="stab portability"]' 'crate feature summate' + // @matches - '//*[@class="stab portability"]' 'crate feature unctuous' + pub trait Gnotobiology { + const XYLOTHERAPY: (); + + #[doc(cfg(feature = "unzymotic"))] + const UNZYMOTIC: (); + + type Lepadoid; + + #[doc(cfg(feature = "summate"))] + type Summate; + + fn decalcomania(); + + #[doc(cfg(feature = "unctuous"))] + fn unctuous(); + } + + // @has 'globuliferous/ratel/trait.Aposiopesis.html' + // @count - '//*[@class="stab portability"]' 4 + // @matches - '//*[@class="stab portability"]' 'crate features ratel and aposiopesis' + // @matches - '//*[@class="stab portability"]' 'crate feature umbracious' + // @matches - '//*[@class="stab portability"]' 'crate feature uakari' + // @matches - '//*[@class="stab portability"]' 'crate feature rotograph' + #[doc(cfg(feature = "aposiopesis"))] + pub trait Aposiopesis { + const REDHIBITION: (); + + #[doc(cfg(feature = "umbracious"))] + const UMBRACIOUS: (); + + type Ophthalmoscope; + + #[doc(cfg(feature = "uakari"))] + type Uakari; + + fn meseems(); + + #[doc(cfg(feature = "rotograph"))] + fn rotograph(); + } +} diff --git a/src/test/rustdoc/doc-cfg.rs b/src/test/rustdoc/doc-cfg.rs index aa407b7e926..d7041ee2f1a 100644 --- a/src/test/rustdoc/doc-cfg.rs +++ b/src/test/rustdoc/doc-cfg.rs @@ -10,9 +10,8 @@ pub struct Portable; // @has doc_cfg/unix_only/index.html \ // '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ // 'This is supported on Unix only.' -// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix\Z' -// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AUnix and ARM\Z' -// @count - '//*[@class="stab portability"]' 3 +// @matches - '//*[@class="module-item"]//*[@class="stab portability"]' '\AARM\Z' +// @count - '//*[@class="stab portability"]' 2 #[doc(cfg(unix))] pub mod unix_only { // @has doc_cfg/unix_only/fn.unix_only_function.html \ @@ -26,7 +25,7 @@ pub mod unix_only { // @has doc_cfg/unix_only/trait.ArmOnly.html \ // '//*[@id="main"]/*[@class="stability"]/*[@class="stab portability"]' \ // 'This is supported on Unix and ARM only.' - // @count - '//*[@class="stab portability"]' 3 + // @count - '//*[@class="stab portability"]' 2 #[doc(cfg(target_arch = "arm"))] pub trait ArmOnly { fn unix_and_arm_only_function(); diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs index 47ba362c977..7b938af3c7d 100644 --- a/src/test/rustdoc/duplicate-cfg.rs +++ b/src/test/rustdoc/duplicate-cfg.rs @@ -14,45 +14,41 @@ pub struct Foo; // @has 'foo/bar/index.html' -// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$' -// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only' - -// @has 'foo/bar/struct.Bar.html' // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub mod bar { + // @has 'foo/bar/struct.Bar.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub struct Bar; } // @has 'foo/baz/index.html' -// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send$' -// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate features `sync` and `send` only' - -// @has 'foo/baz/struct.Baz.html' // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(all(feature = "sync", feature = "send")))] pub mod baz { + // @has 'foo/baz/struct.Baz.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(feature = "sync"))] pub struct Baz; } -// @has 'foo/qux/struct.Qux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' +// @has 'foo/qux/index.html' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub mod qux { + // @has 'foo/qux/struct.Qux.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(all(feature = "sync", feature = "send")))] pub struct Qux; } // @has 'foo/quux/index.html' -// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send and foo and bar$' -// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` and crate feature `send` and `foo` and `bar` only' - -// @has 'foo/quux/struct.Quux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo only.' #[doc(cfg(all(feature = "sync", feature = "send", foo)))] pub mod quux { + // @has 'foo/quux/struct.Quux.html' + // @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.' #[doc(cfg(all(feature = "send", feature = "sync", bar)))] pub struct Quux; } diff --git a/src/test/rustdoc/intra-doc-link-generic-params.rs b/src/test/rustdoc/intra-doc-link-generic-params.rs new file mode 100644 index 00000000000..7d7289437ff --- /dev/null +++ b/src/test/rustdoc/intra-doc-link-generic-params.rs @@ -0,0 +1,59 @@ +// ignore-tidy-linelength + +#![crate_name = "foo"] + +//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`]. +//! Here's a link to [`Iterator<Box<T>>::Item`]. +//! +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html"]' 'Vec<T>' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item' + +//! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)? +//! +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'just Option' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'with the generic, Option<T>' + +//! We should also try linking to [`Result<T, E>`]; it has *two* generics! +//! +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>' + +//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it +//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()]. +//! And what about something even harder? That would be [`Vec::<Box<T>>::new()`]. +//! +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()' + +//! This is also pretty tricky: [`TypeId::of::<String>()`]. +//! And this too: [`Vec::<std::error::Error>::len`]. +//! +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()' +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len' + +//! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like +//! [`Box::<T>new()`]. We may not support them in the future! +//! +// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()' + +//! These will be resolved as regular links: +//! - [`this is <invalid syntax> first`](https://www.rust-lang.org) +//! - [`this is <invalid syntax> twice`] +//! - [`<invalid syntax> thrice`](https://www.rust-lang.org) +//! - [`<invalid syntax> four times`][rlo] +//! - [a < b][rlo] +//! - [c > d] +//! +//! [`this is <invalid syntax> twice`]: https://www.rust-lang.org +//! [rlo]: https://www.rust-lang.org +//! [c > d]: https://www.rust-lang.org +//! +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> first' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> twice' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> thrice' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> four times' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'a < b' +// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'c > d' + +use std::any::TypeId; diff --git a/src/test/rustdoc/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-link-reexport-additional-docs.rs index adb072a7ed5..96f3580f305 100644 --- a/src/test/rustdoc/intra-link-reexport-additional-docs.rs +++ b/src/test/rustdoc/intra-link-reexport-additional-docs.rs @@ -1,6 +1,9 @@ +// aux-build:intra-link-reexport-additional-docs.rs +// build-aux-docs #![crate_name = "foo"] +extern crate inner; -// @has foo/struct.JoinPathsError.html '//a[@href="../foo/fn.with_code.html"]' 'crate::with_code' +// @has foo/struct.Inner.html '//a[@href="../foo/fn.with_code.html"]' 'crate::with_code' /// [crate::with_code] // @has - '//a[@href="../foo/fn.with_code.html"]' 'different text' /// [different text][with_code] @@ -11,7 +14,9 @@ #[doc = "has an attr in the way"] /// /// [reference link]: me_three -pub use std::env::JoinPathsError; +// Should still resolve links from the original module in that scope +// @has - '//a[@href="../inner/fn.f.html"]' 'f()' +pub use inner::Inner; pub fn with_code() {} pub fn me_too() {} diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs index 8f69b894a22..3041ff77684 100644 --- a/src/test/rustdoc/primitive-link.rs +++ b/src/test/rustdoc/primitive-link.rs @@ -7,8 +7,7 @@ // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32' // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str' -// FIXME: this doesn't resolve -// @ has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX' /// It contains [`u32`] and [i64]. /// It also links to [std::primitive::i32], [std::primitive::str], diff --git a/src/test/rustdoc/reexport-check.rs b/src/test/rustdoc/reexport-check.rs index dea72b81a57..066b0cfe5e8 100644 --- a/src/test/rustdoc/reexport-check.rs +++ b/src/test/rustdoc/reexport-check.rs @@ -1,5 +1,8 @@ +// aux-build:reexport-check.rs #![crate_name = "foo"] +extern crate reexport_check; + // @!has 'foo/index.html' '//code' 'pub use self::i32;' // @has 'foo/index.html' '//tr[@class="module-item"]' 'i32' // @has 'foo/i32/index.html' @@ -7,3 +10,8 @@ pub use std::i32; // @!has 'foo/index.html' '//code' 'pub use self::string::String;' // @has 'foo/index.html' '//tr[@class="module-item"]' 'String' pub use std::string::String; + +// @has 'foo/index.html' '//td[@class="docblock-short"]' 'Docs in original' +// this is a no-op, but shows what happens if there's an attribute that isn't a doc-comment +#[doc(inline)] +pub use reexport_check::S; diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs index 0025b47403d..a9520b59277 100644 --- a/src/test/ui-fulldeps/compiler-calls.rs +++ b/src/test/ui-fulldeps/compiler-calls.rs @@ -26,13 +26,8 @@ fn main() { let mut count = 1; let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; rustc_driver::catch_fatal_errors(|| { - rustc_driver::run_compiler( - &args, - &mut TestCalls { count: &mut count }, - None, - None, - None, - ).ok(); - }).ok(); + rustc_driver::RunCompiler::new(&args, &mut TestCalls { count: &mut count }).run().ok(); + }) + .ok(); assert_eq!(count, 2); } diff --git a/src/test/ui/arg-count-mismatch.stderr b/src/test/ui/arg-count-mismatch.stderr index 7bc06134a69..d0577e4864a 100644 --- a/src/test/ui/arg-count-mismatch.stderr +++ b/src/test/ui/arg-count-mismatch.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/arg-count-mismatch.rs:5:28 | -LL | fn f(x: isize) { } - | -------------- defined here -LL | LL | fn main() { let i: (); i = f(); } | ^-- supplied 0 arguments | | | expected 1 argument + | +note: function defined here + --> $DIR/arg-count-mismatch.rs:3:4 + | +LL | fn f(x: isize) { } + | ^ -------- error: aborting due to previous error diff --git a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr index 0ad05b3adeb..7c1a92c79d9 100644 --- a/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr +++ b/src/test/ui/array-slice-vec/match_arr_unknown_len.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/match_arr_unknown_len.rs:6:9 diff --git a/src/test/ui/associated-type-bounds/issue-70292.rs b/src/test/ui/associated-type-bounds/issue-70292.rs new file mode 100644 index 00000000000..945d7688ce6 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-70292.rs @@ -0,0 +1,21 @@ +// check-pass + +#![feature(associated_type_bounds)] + +fn foo<F>(_: F) +where + F: for<'a> Trait<Output: 'a>, +{ +} + +trait Trait { + type Output; +} + +impl<T> Trait for T { + type Output = (); +} + +fn main() { + foo(()); +} diff --git a/src/test/ui/associated-type-bounds/issue-71443-1.rs b/src/test/ui/associated-type-bounds/issue-71443-1.rs new file mode 100644 index 00000000000..5d2a3e6cbad --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-71443-1.rs @@ -0,0 +1,9 @@ +#![feature(associated_type_bounds)] + +struct Incorrect; + +fn hello<F: for<'a> Iterator<Item: 'a>>() { + Incorrect //~ERROR: mismatched types +} + +fn main() {} diff --git a/src/test/ui/associated-type-bounds/issue-71443-1.stderr b/src/test/ui/associated-type-bounds/issue-71443-1.stderr new file mode 100644 index 00000000000..a9459ee7432 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-71443-1.stderr @@ -0,0 +1,11 @@ +error[E0308]: mismatched types + --> $DIR/issue-71443-1.rs:6:5 + | +LL | fn hello<F: for<'a> Iterator<Item: 'a>>() { + | - help: try adding a return type: `-> Incorrect` +LL | Incorrect + | ^^^^^^^^^ expected `()`, found struct `Incorrect` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/associated-type-bounds/issue-71443-2.rs b/src/test/ui/associated-type-bounds/issue-71443-2.rs new file mode 100644 index 00000000000..813dcd60ad1 --- /dev/null +++ b/src/test/ui/associated-type-bounds/issue-71443-2.rs @@ -0,0 +1,11 @@ +// check-pass + +#![feature(associated_type_bounds)] + +fn hello<'b, F>() +where + for<'a> F: Iterator<Item: 'a> + 'b, +{ +} + +fn main() {} diff --git a/src/test/ui/associated-types/defaults-specialization.stderr b/src/test/ui/associated-types/defaults-specialization.stderr index 09a8c8f8a88..920f8322813 100644 --- a/src/test/ui/associated-types/defaults-specialization.stderr +++ b/src/test/ui/associated-types/defaults-specialization.stderr @@ -6,6 +6,7 @@ LL | #![feature(associated_type_defaults, specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0053]: method `make` has an incompatible type for trait --> $DIR/defaults-specialization.rs:19:18 diff --git a/src/test/ui/associated-types/issue-54108.rs b/src/test/ui/associated-types/issue-54108.rs new file mode 100644 index 00000000000..87f67ce4b52 --- /dev/null +++ b/src/test/ui/associated-types/issue-54108.rs @@ -0,0 +1,41 @@ +use std::ops::Add; + +pub trait Encoder { + type Size: Add<Output = Self::Size>; + + fn foo(&self) -> Self::Size; +} + +pub trait SubEncoder: Encoder { + type ActualSize; + + fn bar(&self) -> Self::Size; +} + +impl<T> Encoder for T +where + T: SubEncoder, +{ + type Size = <Self as SubEncoder>::ActualSize; + //~^ ERROR: cannot add `<T as SubEncoder>::ActualSize` to `<T as SubEncoder>::ActualSize` + + fn foo(&self) -> Self::Size { + self.bar() + self.bar() + } +} + +pub struct UnitEncoder; + +impl SubEncoder for UnitEncoder { + type ActualSize = (); + + fn bar(&self) {} +} + +pub fn fun<R: Encoder>(encoder: &R) { + encoder.foo(); +} + +fn main() { + fun(&UnitEncoder {}); +} diff --git a/src/test/ui/associated-types/issue-54108.stderr b/src/test/ui/associated-types/issue-54108.stderr new file mode 100644 index 00000000000..927a2de9965 --- /dev/null +++ b/src/test/ui/associated-types/issue-54108.stderr @@ -0,0 +1,18 @@ +error[E0277]: cannot add `<T as SubEncoder>::ActualSize` to `<T as SubEncoder>::ActualSize` + --> $DIR/issue-54108.rs:19:5 + | +LL | type Size: Add<Output = Self::Size>; + | ------------------------ required by this bound in `Encoder::Size` +... +LL | type Size = <Self as SubEncoder>::ActualSize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `<T as SubEncoder>::ActualSize + <T as SubEncoder>::ActualSize` + | + = help: the trait `Add` is not implemented for `<T as SubEncoder>::ActualSize` +help: consider further restricting the associated type + | +LL | T: SubEncoder, <T as SubEncoder>::ActualSize: Add + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/issue-65934.rs b/src/test/ui/associated-types/issue-65934.rs new file mode 100644 index 00000000000..e17b11c5eae --- /dev/null +++ b/src/test/ui/associated-types/issue-65934.rs @@ -0,0 +1,17 @@ +// check-pass + +trait Trait { + type Assoc; +} + +impl Trait for () { + type Assoc = (); +} + +fn unit() -> impl Into<<() as Trait>::Assoc> {} + +pub fn ice() { + Into::into(unit()); +} + +fn main() {} diff --git a/src/test/ui/binding/const-param.stderr b/src/test/ui/binding/const-param.stderr index 316fac62325..d3d06a2d834 100644 --- a/src/test/ui/binding/const-param.stderr +++ b/src/test/ui/binding/const-param.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0158]: const parameters cannot be referenced in patterns --> $DIR/const-param.rs:7:9 diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs index b67d494866b..97f96ab6929 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs @@ -3,8 +3,6 @@ #![feature(or_patterns)] #![feature(box_patterns)] -#![feature(move_ref_pattern)] - enum Test { Foo, Bar, diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index 1bf81589275..96e313b39ed 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:40:9 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:38:9 | LL | ref foo @ [.., ref mut bar] => (), | -------^^^^^^^^-----------^ @@ -8,7 +8,7 @@ LL | ref foo @ [.., ref mut bar] => (), | immutable borrow, by `foo`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:124:9 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:122:9 | LL | ref foo @ Some(box ref mut s) => (), | -------^^^^^^^^^^^^---------^ @@ -17,7 +17,7 @@ LL | ref foo @ Some(box ref mut s) => (), | immutable borrow, by `foo`, occurs here error[E0382]: borrow of moved value: `x` - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:22:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:20:5 | LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { | - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ LL | &x; | ^^ value borrowed here after move error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:32:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:30:5 | LL | ref mut foo @ [.., _] => Some(foo), | --------------------- mutable borrow occurs here @@ -41,7 +41,7 @@ LL | drop(r); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:54:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:52:5 | LL | [ref foo @ .., ref bar] => Some(foo), | ------------ immutable borrow occurs here @@ -53,7 +53,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:66:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:64:5 | LL | ref foo @ [.., ref bar] => Some(foo), | ----------------------- immutable borrow occurs here @@ -65,7 +65,7 @@ LL | drop(r); | - immutable borrow later used here error[E0382]: borrow of moved value: `x` - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:80:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:78:5 | LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) { | - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait @@ -80,7 +80,7 @@ LL | &x; | ^^ value borrowed here after move error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:90:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:88:5 | LL | ref foo @ Some(Test::Foo | Test::Bar) => Some(foo), | ------------------------------------- immutable borrow occurs here @@ -92,7 +92,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:102:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:100:5 | LL | ref mut foo @ Some(Test::Foo | Test::Bar) => Some(foo), | ----------------------------------------- mutable borrow occurs here @@ -104,7 +104,7 @@ LL | drop(r); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:116:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:114:5 | LL | ref foo @ Some(box ref s) => Some(foo), | ------------------------- immutable borrow occurs here @@ -116,7 +116,7 @@ LL | drop(r); | - immutable borrow later used here error[E0382]: borrow of moved value: `x` - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:138:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:136:5 | LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4]) { | - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait @@ -131,7 +131,7 @@ LL | &x; | ^^ value borrowed here after move error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:148:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:146:5 | LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(a), | ------------------------------------------------- immutable borrow occurs here @@ -143,7 +143,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:160:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:158:5 | LL | ref a @ [ref b @ .., Some(Test::Foo | Test::Bar)] => Some(b), | ---------- immutable borrow occurs here @@ -155,7 +155,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:174:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:172:5 | LL | [_, ref a @ Some(box ref b), ..] => Some(a), | ----------------------- immutable borrow occurs here @@ -167,7 +167,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:190:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:188:5 | LL | [_, ref a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), | ------------------------------------------- immutable borrow occurs here @@ -179,7 +179,7 @@ LL | drop(r); | - immutable borrow later used here error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:204:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:202:5 | LL | [_, ref mut a @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), | ----------------------------------------------- mutable borrow occurs here @@ -191,7 +191,7 @@ LL | drop(r); | - mutable borrow later used here error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable - --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:218:5 + --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:216:5 | LL | ref a @ [_, ref b @ Some(box Test::Foo | box Test::Bar), ..] => Some(a), | ------------------------------------------------------------ immutable borrow occurs here diff --git a/src/test/ui/c-variadic/variadic-ffi-1.stderr b/src/test/ui/c-variadic/variadic-ffi-1.stderr index 89ea65fd43f..6f2a6c359b5 100644 --- a/src/test/ui/c-variadic/variadic-ffi-1.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-1.stderr @@ -7,24 +7,30 @@ LL | fn printf(_: *const u8, ...); error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied --> $DIR/variadic-ffi-1.rs:17:9 | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... LL | foo(); | ^^^-- supplied 0 arguments | | | expected at least 2 arguments + | +note: function defined here + --> $DIR/variadic-ffi-1.rs:10:8 + | +LL | fn foo(f: isize, x: u8, ...); + | ^^^ error[E0060]: this function takes at least 2 arguments but 1 argument was supplied --> $DIR/variadic-ffi-1.rs:18:9 | -LL | fn foo(f: isize, x: u8, ...); - | ----------------------------- defined here -... LL | foo(1); | ^^^ - supplied 1 argument | | | expected at least 2 arguments + | +note: function defined here + --> $DIR/variadic-ffi-1.rs:10:8 + | +LL | fn foo(f: isize, x: u8, ...); + | ^^^ error[E0308]: mismatched types --> $DIR/variadic-ffi-1.rs:20:56 diff --git a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr index 7af38c88f43..e11ba43ca2a 100644 --- a/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-no-fixed-args.stderr @@ -2,7 +2,7 @@ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-no-fixed-args.rs:2:12 | LL | fn foo(...); - | ^^^^ + | ^^^ error: aborting due to previous error diff --git a/src/test/ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs index c8bec39fad6..0ca2349a43b 100644 --- a/src/test/ui/check-doc-alias-attr.rs +++ b/src/test/ui/check-doc-alias-attr.rs @@ -11,6 +11,7 @@ pub struct Bar; #[doc(alias = "\n")] //~ ERROR #[doc(alias = " ")] //~^ ERROR -#[doc(alias = " ")] //~ ERROR #[doc(alias = "\t")] //~ ERROR +#[doc(alias = " hello")] //~ ERROR +#[doc(alias = "hello ")] //~ ERROR pub struct Foo; diff --git a/src/test/ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr index be7d7b3dbea..2c417a3bb65 100644 --- a/src/test/ui/check-doc-alias-attr.stderr +++ b/src/test/ui/check-doc-alias-attr.stderr @@ -36,17 +36,23 @@ LL | #[doc(alias = " LL | | ")] | |_^ -error: ' ' character isn't allowed in `#[doc(alias = "...")]` +error: '\t' character isn't allowed in `#[doc(alias = "...")]` --> $DIR/check-doc-alias-attr.rs:14:7 | -LL | #[doc(alias = " ")] - | ^^^^^^^^^^^ +LL | #[doc(alias = "\t")] + | ^^^^^^^^^^^^ -error: '\t' character isn't allowed in `#[doc(alias = "...")]` +error: `#[doc(alias = "...")]` cannot start or end with ' ' --> $DIR/check-doc-alias-attr.rs:15:7 | -LL | #[doc(alias = "\t")] - | ^^^^^^^^^^^^ +LL | #[doc(alias = " hello")] + | ^^^^^^^^^^^^^^^^ + +error: `#[doc(alias = "...")]` cannot start or end with ' ' + --> $DIR/check-doc-alias-attr.rs:16:7 + | +LL | #[doc(alias = "hello ")] + | ^^^^^^^^^^^^^^^^ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr index 7e140480b77..f3edf1c350f 100644 --- a/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr +++ b/src/test/ui/coherence/coherence-inherited-assoc-ty-cycle-err.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0391]: cycle detected when building specialization graph of trait `Trait` --> $DIR/coherence-inherited-assoc-ty-cycle-err.rs:9:1 diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr index 0fc45513cd7..cfaacf7a5be 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/array-size-in-generic-struct-param.rs:9:48 | LL | struct ArithArrayLen<const N: usize>([u32; 0 + N]); - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/array-size-in-generic-struct-param.rs:20:15 | LL | arr: [u8; CFG.arr_size], - | ^^^ non-trivial anonymous constants must not depend on the parameter `CFG` + | ^^^ cannot perform const operation using `CFG` | - = help: it is currently only allowed to use either `CFG` or `{ CFG }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `CFG` error: `Config` is forbidden as the type of a const generic parameter --> $DIR/array-size-in-generic-struct-param.rs:18:21 diff --git a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs index dd45b6ed278..768180d0813 100644 --- a/src/test/ui/const-generics/array-size-in-generic-struct-param.rs +++ b/src/test/ui/const-generics/array-size-in-generic-struct-param.rs @@ -8,7 +8,7 @@ #[allow(dead_code)] struct ArithArrayLen<const N: usize>([u32; 0 + N]); //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ ERROR generic parameters may not be used in const operations #[derive(PartialEq, Eq)] struct Config { @@ -19,7 +19,7 @@ struct B<const CFG: Config> { //[min]~^ ERROR `Config` is forbidden arr: [u8; CFG.arr_size], //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial + //[min]~^^ ERROR generic parameters may not be used in const operations } const C: Config = Config { arr_size: 5 }; diff --git a/src/test/ui/const-generics/const-argument-if-length.min.stderr b/src/test/ui/const-generics/const-argument-if-length.min.stderr index c666dce479f..bce701ade86 100644 --- a/src/test/ui/const-generics/const-argument-if-length.min.stderr +++ b/src/test/ui/const-generics/const-argument-if-length.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/const-argument-if-length.rs:19:24 | LL | pad: [u8; is_zst::<T>()], - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0277]: the size for values of type `T` cannot be known at compilation time --> $DIR/const-argument-if-length.rs:17:12 diff --git a/src/test/ui/const-generics/const-argument-if-length.rs b/src/test/ui/const-generics/const-argument-if-length.rs index 481ff97d68d..a8bffd17b91 100644 --- a/src/test/ui/const-generics/const-argument-if-length.rs +++ b/src/test/ui/const-generics/const-argument-if-length.rs @@ -17,7 +17,7 @@ pub struct AtLeastByte<T: ?Sized> { value: T, //~^ ERROR the size for values of type `T` cannot be known at compilation time pad: [u8; is_zst::<T>()], - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR evaluation of constant value failed } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr index 4b3235fd087..359c2d2a22f 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33 | LL | type Arr<const N: usize> = [u8; N - 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs index d552e0f5430..9746adab29b 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs @@ -4,7 +4,7 @@ #![cfg_attr(min, feature(min_const_generics))] type Arr<const N: usize> = [u8; N - 1]; -//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^ ERROR generic parameters may not be used in const operations fn test<const N: usize>() -> Arr<N> where Arr<N>: Default { //[full]~^ ERROR constant expression depends diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr index 85a15b1e75f..46485262cc4 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/simple.rs:8:53 | LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default { - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/simple.rs:8:35 | LL | fn test<const N: usize>() -> [u8; N - 1] where [u8; N - 1]: Default { - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr index 2eac9505624..981d993f589 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/simple_fail.rs:7:33 | LL | type Arr<const N: usize> = [u8; N - 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs index 637c940f714..5e2c080927f 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -5,7 +5,7 @@ #![allow(incomplete_features)] type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant -//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^ ERROR generic parameters may not be used in const operations fn test<const N: usize>() -> Arr<N> where Arr<N>: Sized { todo!() diff --git a/src/test/ui/const-generics/defaults/wrong-order.full.stderr b/src/test/ui/const-generics/defaults/wrong-order.full.stderr index c51028d5b20..99f46309bf6 100644 --- a/src/test/ui/const-generics/defaults/wrong-order.full.stderr +++ b/src/test/ui/const-generics/defaults/wrong-order.full.stderr @@ -14,6 +14,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr index e7e968e4c2a..84449018e46 100644 --- a/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr +++ b/src/test/ui/const-generics/generic-function-call-in-array-length.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/generic-function-call-in-array-length.rs:9:39 | LL | fn bar<const N: usize>() -> [u32; foo(N)] { - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/generic-function-call-in-array-length.rs:12:13 | LL | [0; foo(N)] - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/generic-function-call-in-array-length.rs b/src/test/ui/const-generics/generic-function-call-in-array-length.rs index c8bbae29343..c838070dc95 100644 --- a/src/test/ui/const-generics/generic-function-call-in-array-length.rs +++ b/src/test/ui/const-generics/generic-function-call-in-array-length.rs @@ -7,10 +7,10 @@ const fn foo(n: usize) -> usize { n * 2 } fn bar<const N: usize>() -> [u32; foo(N)] { - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR constant expression depends on a generic parameter [0; foo(N)] - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations } fn main() {} diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr index 6f157fbbbbb..d3f7143327e 100644 --- a/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr +++ b/src/test/ui/const-generics/generic-sum-in-array-length.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/generic-sum-in-array-length.rs:7:53 | LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {} - | ^ non-trivial anonymous constants must not depend on the parameter `A` + | ^ cannot perform const operation using `A` | - = help: it is currently only allowed to use either `A` or `{ A }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `A` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/generic-sum-in-array-length.rs:7:57 | LL | fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {} - | ^ non-trivial anonymous constants must not depend on the parameter `B` + | ^ cannot perform const operation using `B` | - = help: it is currently only allowed to use either `B` or `{ B }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `B` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/generic-sum-in-array-length.rs b/src/test/ui/const-generics/generic-sum-in-array-length.rs index 810095b384b..84ddfe055dc 100644 --- a/src/test/ui/const-generics/generic-sum-in-array-length.rs +++ b/src/test/ui/const-generics/generic-sum-in-array-length.rs @@ -5,8 +5,8 @@ #![cfg_attr(min, feature(min_const_generics))] fn foo<const A: usize, const B: usize>(bar: [usize; A + B]) {} -//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values -//[min]~| ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^ ERROR generic parameters may not be used in const operations +//[min]~| ERROR generic parameters may not be used in const operations //[full]~^^^ ERROR constant expression depends on a generic parameter fn main() {} diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr index 307db088bf8..20a8d9fdaab 100644 --- a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr +++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/intrinsics-type_name-as-const-argument.rs:15:44 | LL | T: Trait<{std::intrinsics::type_name::<T>()}> - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in 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 diff --git a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs index 37b6cf4bab9..8971c00ed5a 100644 --- a/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs +++ b/src/test/ui/const-generics/intrinsics-type_name-as-const-argument.rs @@ -13,7 +13,7 @@ trait Trait<const S: &'static str> {} struct Bug<T> where T: Trait<{std::intrinsics::type_name::<T>()}> - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR constant expression depends on a generic parameter { t: T diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr index 2c1bc055b28..526807f0a24 100644 --- a/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr +++ b/src/test/ui/const-generics/issue-61522-array-len-succ.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-61522-array-len-succ.rs:7:45 | LL | pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]); - | ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT` + | ^^^^^ cannot perform const operation using `COUNT` | - = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `COUNT` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-61522-array-len-succ.rs:12:30 | LL | fn inner(&self) -> &[u8; COUNT + 1] { - | ^^^^^ non-trivial anonymous constants must not depend on the parameter `COUNT` + | ^^^^^ cannot perform const operation using `COUNT` | - = help: it is currently only allowed to use either `COUNT` or `{ COUNT }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `COUNT` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issue-61522-array-len-succ.rs b/src/test/ui/const-generics/issue-61522-array-len-succ.rs index 81443b90d61..8c0a3a03774 100644 --- a/src/test/ui/const-generics/issue-61522-array-len-succ.rs +++ b/src/test/ui/const-generics/issue-61522-array-len-succ.rs @@ -6,12 +6,12 @@ pub struct MyArray<const COUNT: usize>([u8; COUNT + 1]); //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used +//[min]~^^ ERROR generic parameters may not be used impl<const COUNT: usize> MyArray<COUNT> { fn inner(&self) -> &[u8; COUNT + 1] { //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used + //[min]~^^ ERROR generic parameters may not be used &self.0 } } diff --git a/src/test/ui/const-generics/issue-67375.min.stderr b/src/test/ui/const-generics/issue-67375.min.stderr index b13d9fdab0d..3c344edbf1d 100644 --- a/src/test/ui/const-generics/issue-67375.min.stderr +++ b/src/test/ui/const-generics/issue-67375.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67375.rs:9:25 | LL | inner: [(); { [|_: &T| {}; 0].len() }], - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0392]: parameter `T` is never used --> $DIR/issue-67375.rs:7:12 diff --git a/src/test/ui/const-generics/issue-67375.rs b/src/test/ui/const-generics/issue-67375.rs index 994ec92cfb5..ecc76bcae06 100644 --- a/src/test/ui/const-generics/issue-67375.rs +++ b/src/test/ui/const-generics/issue-67375.rs @@ -7,7 +7,7 @@ struct Bug<T> { //~^ ERROR parameter `T` is never used inner: [(); { [|_: &T| {}; 0].len() }], - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ WARN cannot use constants which depend on generic parameters in types //[full]~^^^ WARN this was previously accepted by the compiler } diff --git a/src/test/ui/const-generics/issue-67945-1.min.stderr b/src/test/ui/const-generics/issue-67945-1.min.stderr index 949b5da5920..804236c30bd 100644 --- a/src/test/ui/const-generics/issue-67945-1.min.stderr +++ b/src/test/ui/const-generics/issue-67945-1.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67945-1.rs:14:16 | LL | let x: S = MaybeUninit::uninit(); - | ^ non-trivial anonymous constants must not depend on the parameter `S` + | ^ cannot perform const operation using `S` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67945-1.rs:17:45 | LL | let b = &*(&x as *const _ as *const S); - | ^ non-trivial anonymous constants must not depend on the parameter `S` + | ^ cannot perform const operation using `S` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0392]: parameter `S` is never used --> $DIR/issue-67945-1.rs:11:12 diff --git a/src/test/ui/const-generics/issue-67945-1.rs b/src/test/ui/const-generics/issue-67945-1.rs index d1a83e978d1..6771603f259 100644 --- a/src/test/ui/const-generics/issue-67945-1.rs +++ b/src/test/ui/const-generics/issue-67945-1.rs @@ -12,10 +12,10 @@ struct Bug<S> { //~^ ERROR parameter `S` is never used A: [(); { let x: S = MaybeUninit::uninit(); - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR mismatched types let b = &*(&x as *const _ as *const S); - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations 0 }], } diff --git a/src/test/ui/const-generics/issue-67945-2.min.stderr b/src/test/ui/const-generics/issue-67945-2.min.stderr index ed445b3e8f7..2de942c1220 100644 --- a/src/test/ui/const-generics/issue-67945-2.min.stderr +++ b/src/test/ui/const-generics/issue-67945-2.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67945-2.rs:12:16 | LL | let x: S = MaybeUninit::uninit(); - | ^ non-trivial anonymous constants must not depend on the parameter `S` + | ^ cannot perform const operation using `S` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67945-2.rs:15:45 | LL | let b = &*(&x as *const _ as *const S); - | ^ non-trivial anonymous constants must not depend on the parameter `S` + | ^ cannot perform const operation using `S` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0392]: parameter `S` is never used --> $DIR/issue-67945-2.rs:9:12 diff --git a/src/test/ui/const-generics/issue-67945-2.rs b/src/test/ui/const-generics/issue-67945-2.rs index 7f789297df0..72dbb674e66 100644 --- a/src/test/ui/const-generics/issue-67945-2.rs +++ b/src/test/ui/const-generics/issue-67945-2.rs @@ -10,10 +10,10 @@ struct Bug<S> { //~^ ERROR parameter `S` is never used A: [(); { let x: S = MaybeUninit::uninit(); - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations //[full]~^^ ERROR mismatched types let b = &*(&x as *const _ as *const S); - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations 0 }], } diff --git a/src/test/ui/const-generics/issues/issue-56445.full.stderr b/src/test/ui/const-generics/issues/issue-56445.full.stderr index d853ec5015e..50e91418551 100644 --- a/src/test/ui/const-generics/issues/issue-56445.full.stderr +++ b/src/test/ui/const-generics/issues/issue-56445.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0771]: use of non-static lifetime `'a` in const generic --> $DIR/issue-56445.rs:9:26 diff --git a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr index c03b7252a3c..cc014ea429d 100644 --- a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr +++ b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61336-1.full.stderr b/src/test/ui/const-generics/issues/issue-61336-1.full.stderr index f18728eabbb..3a9f819a626 100644 --- a/src/test/ui/const-generics/issues/issue-61336-1.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-1.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr index ef6e60084a5..883ebbef3e8 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336-2.rs:10:5 diff --git a/src/test/ui/const-generics/issues/issue-61336.full.stderr b/src/test/ui/const-generics/issues/issue-61336.full.stderr index bdfdffd941d..3863da8da05 100644 --- a/src/test/ui/const-generics/issues/issue-61336.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336.rs:10:5 diff --git a/src/test/ui/const-generics/issues/issue-61422.full.stderr b/src/test/ui/const-generics/issues/issue-61422.full.stderr index ac6c378295d..294378a6690 100644 --- a/src/test/ui/const-generics/issues/issue-61422.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61422.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61432.full.stderr b/src/test/ui/const-generics/issues/issue-61432.full.stderr index 82b36de45a2..eec1b20254e 100644 --- a/src/test/ui/const-generics/issues/issue-61432.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61432.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61747.full.stderr b/src/test/ui/const-generics/issues/issue-61747.full.stderr index 3ccce5675fc..3a266c8e974 100644 --- a/src/test/ui/const-generics/issues/issue-61747.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61747.full.stderr @@ -6,6 +6,7 @@ LL | #![cfg_attr(full, feature(const_generics))] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: constant expression depends on a generic parameter --> $DIR/issue-61747.rs:8:23 diff --git a/src/test/ui/const-generics/issues/issue-61747.min.stderr b/src/test/ui/const-generics/issues/issue-61747.min.stderr index fdd9a569748..b176f9d1c75 100644 --- a/src/test/ui/const-generics/issues/issue-61747.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61747.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-61747.rs:8:30 | LL | fn successor() -> Const<{C + 1}> { - | ^ non-trivial anonymous constants must not depend on the parameter `C` + | ^ cannot perform const operation using `C` | - = help: it is currently only allowed to use either `C` or `{ C }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `C` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs index 4e5cde17f39..3a4dd1cdd18 100644 --- a/src/test/ui/const-generics/issues/issue-61747.rs +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -7,7 +7,7 @@ struct Const<const N: usize>; impl<const C: usize> Const<{C}> { fn successor() -> Const<{C + 1}> { //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used + //[min]~^^ ERROR generic parameters may not be used Const } } diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr index f461a31eeae..9e31466259f 100644 --- a/src/test/ui/const-generics/issues/issue-61935.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-61935.rs:10:23 | LL | Self:FooImpl<{N==0}> - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs index a181a8dabe5..9fa02329a71 100644 --- a/src/test/ui/const-generics/issues/issue-61935.rs +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -9,7 +9,7 @@ impl<const N: usize> Foo for [(); N] where Self:FooImpl<{N==0}> //[full]~^ERROR constant expression depends on a generic parameter -//[min]~^^ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ERROR generic parameters may not be used in const operations {} trait FooImpl<const IS_ZERO: bool>{} diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr index 84975e8f3be..3bd127ee74a 100644 --- a/src/test/ui/const-generics/issues/issue-62220.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-62220.rs:8:59 | LL | pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs index 5694dc6d04d..2017473fa9e 100644 --- a/src/test/ui/const-generics/issues/issue-62220.rs +++ b/src/test/ui/const-generics/issues/issue-62220.rs @@ -6,7 +6,7 @@ pub struct Vector<T, const N: usize>([T; N]); pub type TruncatedVector<T, const N: usize> = Vector<T, { N - 1 }>; -//[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^ ERROR generic parameters may not be used in const operations impl<T, const N: usize> Vector<T, { N }> { /// Drop the last component and return the vector with one fewer dimension. diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr index f94ba8c0c9b..c73f62a4a07 100644 --- a/src/test/ui/const-generics/issues/issue-62456.min.stderr +++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-62456.rs:7:20 | LL | let _ = [0u64; N + 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs index 338ec42799d..cbb2a11a931 100644 --- a/src/test/ui/const-generics/issues/issue-62456.rs +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -6,7 +6,7 @@ fn foo<const N: usize>() { let _ = [0u64; N + 1]; //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-64494.min.stderr b/src/test/ui/const-generics/issues/issue-64494.min.stderr index f712171bbac..8b02fd108bd 100644 --- a/src/test/ui/const-generics/issues/issue-64494.min.stderr +++ b/src/test/ui/const-generics/issues/issue-64494.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-64494.rs:16:38 | LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {} - | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` + | ^^^^^^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-64494.rs:19:38 | LL | impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {} - | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` + | ^^^^^^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error[E0119]: conflicting implementations of trait `MyTrait`: --> $DIR/issue-64494.rs:19:1 diff --git a/src/test/ui/const-generics/issues/issue-64494.rs b/src/test/ui/const-generics/issues/issue-64494.rs index b62ebf846d5..014742be03d 100644 --- a/src/test/ui/const-generics/issues/issue-64494.rs +++ b/src/test/ui/const-generics/issues/issue-64494.rs @@ -15,10 +15,10 @@ impl True for Is<{true}> {} impl<T: Foo> MyTrait for T where Is<{T::VAL == 5}>: True {} //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ ERROR generic parameters may not be used in const operations impl<T: Foo> MyTrait for T where Is<{T::VAL == 6}>: True {} //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ ERROR generic parameters may not be used in const operations //[min]~| ERROR conflicting implementations of trait `MyTrait` fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-66205.min.stderr b/src/test/ui/const-generics/issues/issue-66205.min.stderr index a18126ccfef..282f72be6da 100644 --- a/src/test/ui/const-generics/issues/issue-66205.min.stderr +++ b/src/test/ui/const-generics/issues/issue-66205.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-66205.rs:8:14 | LL | fact::<{ N - 1 }>(); - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 668f49852e1..4e37c247d00 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -7,7 +7,7 @@ fn fact<const N: usize>() { fact::<{ N - 1 }>(); //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr index ba378de4156..35d97c46248 100644 --- a/src/test/ui/const-generics/issues/issue-67739.min.stderr +++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-67739.rs:12:30 | LL | [0u8; mem::size_of::<Self::Associated>()]; - | ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | ^^^^^^^^^^^^^^^^ cannot perform const operation using `Self` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index 296e4d423c4..21d13de22eb 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -11,7 +11,7 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::<Self::Associated>()]; //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations 0 } } diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr index 73d6fec6f9b..b900a0d096a 100644 --- a/src/test/ui/const-generics/issues/issue-68366.min.stderr +++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-68366.rs:12:37 | LL | impl <const N: usize> Collatz<{Some(N)}> {} - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates --> $DIR/issue-68366.rs:12:13 diff --git a/src/test/ui/const-generics/issues/issue-68366.rs b/src/test/ui/const-generics/issues/issue-68366.rs index ac313eb3b2f..474cdb7258d 100644 --- a/src/test/ui/const-generics/issues/issue-68366.rs +++ b/src/test/ui/const-generics/issues/issue-68366.rs @@ -11,7 +11,7 @@ struct Collatz<const N: Option<usize>>; impl <const N: usize> Collatz<{Some(N)}> {} //~^ ERROR the const parameter -//[min]~^^ generic parameters must not be used inside of non-trivial constant values +//[min]~^^ generic parameters may not be used in const operations struct Foo; diff --git a/src/test/ui/const-generics/issues/issue-68977.min.stderr b/src/test/ui/const-generics/issues/issue-68977.min.stderr index 59d2be3ce4b..7828d859394 100644 --- a/src/test/ui/const-generics/issues/issue-68977.min.stderr +++ b/src/test/ui/const-generics/issues/issue-68977.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-68977.rs:29:17 | LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; - | ^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `INT_BITS` + | ^^^^^^^^ cannot perform const operation using `INT_BITS` | - = help: it is currently only allowed to use either `INT_BITS` or `{ INT_BITS }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `INT_BITS` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-68977.rs:29:28 | LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; - | ^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `FRAC_BITS` + | ^^^^^^^^^ cannot perform const operation using `FRAC_BITS` | - = help: it is currently only allowed to use either `FRAC_BITS` or `{ FRAC_BITS }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `FRAC_BITS` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs index 49b305a5a78..4fea94cb465 100644 --- a/src/test/ui/const-generics/issues/issue-68977.rs +++ b/src/test/ui/const-generics/issues/issue-68977.rs @@ -27,8 +27,8 @@ fxp_storage_impls! { type FxpStorageHelper<const INT_BITS: u8, const FRAC_BITS: u8> = PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; - //[min]~^ ERROR generic parameters must not be used inside of non-trivial constant values - //[min]~| ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^ ERROR generic parameters may not be used in const operations + //[min]~| ERROR generic parameters may not be used in const operations struct Fxp<const INT_BITS: u8, const FRAC_BITS: u8> where diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr index a4c80b1d8c0..d960d9513b7 100644 --- a/src/test/ui/const-generics/issues/issue-72787.min.stderr +++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr @@ -1,34 +1,34 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:11:17 | LL | Condition<{ LHS <= RHS }>: True - | ^^^ non-trivial anonymous constants must not depend on the parameter `LHS` + | ^^^ cannot perform const operation using `LHS` | - = help: it is currently only allowed to use either `LHS` or `{ LHS }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `LHS` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:11:24 | LL | Condition<{ LHS <= RHS }>: True - | ^^^ non-trivial anonymous constants must not depend on the parameter `RHS` + | ^^^ cannot perform const operation using `RHS` | - = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `RHS` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:26:25 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, - | ^ non-trivial anonymous constants must not depend on the parameter `I` + | ^ cannot perform const operation using `I` | - = help: it is currently only allowed to use either `I` or `{ I }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `I` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72787.rs:26:36 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, - | ^ non-trivial anonymous constants must not depend on the parameter `J` + | ^ cannot perform const operation using `J` | - = help: it is currently only allowed to use either `J` or `{ J }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `J` error[E0283]: type annotations needed --> $DIR/issue-72787.rs:22:26 diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs index 779c1d2950e..57572e23aa4 100644 --- a/src/test/ui/const-generics/issues/issue-72787.rs +++ b/src/test/ui/const-generics/issues/issue-72787.rs @@ -10,8 +10,8 @@ pub trait True {} impl<const LHS: u32, const RHS: u32> True for IsLessOrEqual<LHS, RHS> where Condition<{ LHS <= RHS }>: True //[full]~^ Error constant expression depends on a generic parameter -//[min]~^^ Error generic parameters must not be used inside of non-trivial constant values -//[min]~| Error generic parameters must not be used inside of non-trivial constant values +//[min]~^^ Error generic parameters may not be used in const operations +//[min]~| Error generic parameters may not be used in const operations { } impl True for Condition<true> {} @@ -28,8 +28,8 @@ where //[full]~| constant expression depends on a generic parameter //[full]~| constant expression depends on a generic parameter //[full]~| constant expression depends on a generic parameter -//[min]~^^^^^ Error generic parameters must not be used inside of non-trivial constant values -//[min]~| Error generic parameters must not be used inside of non-trivial constant values +//[min]~^^^^^ Error generic parameters may not be used in const operations +//[min]~| Error generic parameters may not be used in const operations // Condition<{ 8 - I <= 8 - J }>: True, { fn print() { diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr index afc14c7dcff..9fec3eb946d 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-72819-generic-in-const-eval.rs:9:17 | LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs index 65c7f00a72a..6182042bde7 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs @@ -8,7 +8,7 @@ struct Arr<const N: usize> where Assert::<{N < usize::max_value() / 2}>: IsTrue, //[full]~^ ERROR constant expression depends on a generic parameter -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values +//[min]~^^ ERROR generic parameters may not be used in const operations { } diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr index 0db948d0a45..c10db84ea6e 100644 --- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-76701-ty-param-in-const.rs:6:46 | LL | fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] { - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/issue-76701-ty-param-in-const.rs:12:42 | LL | fn const_param<const N: usize>() -> [u8; N + 1] { - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs index 3c5bfb03f08..9051c36fe81 100644 --- a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs @@ -5,13 +5,13 @@ fn ty_param<T>() -> [u8; std::mem::size_of::<T>()] { //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations todo!() } fn const_param<const N: usize>() -> [u8; N + 1] { //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial constant values + //[min]~^^ ERROR generic parameters may not be used in const operations todo!() } diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.rs b/src/test/ui/const-generics/min_const_generics/complex-expression.rs index c6380f6394d..8257ffbf491 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-expression.rs +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.rs @@ -7,19 +7,19 @@ fn ok<const M: usize>() -> [u8; M] { } struct Break0<const N: usize>([u8; { N + 1 }]); -//~^ ERROR generic parameters must not be used inside of non-trivial constant values +//~^ ERROR generic parameters may not be used in const operations struct Break1<const N: usize>([u8; { { N } }]); -//~^ ERROR generic parameters must not be used inside of non-trivial constant values +//~^ ERROR generic parameters may not be used in const operations fn break2<const N: usize>() { let _: [u8; N + 1]; - //~^ ERROR generic parameters must not be used inside of non-trivial constant values + //~^ ERROR generic parameters may not be used in const operations } fn break3<const N: usize>() { let _ = [0; N + 1]; - //~^ ERROR generic parameters must not be used inside of non-trivial constant values + //~^ ERROR generic parameters may not be used in const operations } trait Foo { diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr index d8897f53d7f..73768ac03a4 100644 --- a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr @@ -1,34 +1,34 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:9:38 | LL | struct Break0<const N: usize>([u8; { N + 1 }]); - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:12:40 | LL | struct Break1<const N: usize>([u8; { { N } }]); - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:16:17 | LL | let _: [u8; N + 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/complex-expression.rs:21:17 | LL | let _ = [0; N + 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 4 previous errors diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr index 7dc81bf45af..64da5e07df2 100644 --- a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -1,10 +1,10 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/self-ty-in-const-1.rs:4:41 | LL | fn t1() -> [u8; std::mem::size_of::<Self>()]; - | ^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | ^^^^ cannot perform const operation using `Self` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error: generic `Self` types are currently not permitted in anonymous constants --> $DIR/self-ty-in-const-1.rs:14:41 diff --git a/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr index 671f1103dcc..8a1462c59e8 100644 --- a/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr +++ b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: constant expression depends on a generic parameter --> $DIR/unify-fixpoint.rs:9:32 diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr index 0dd591d891f..39aa8087cec 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr @@ -6,13 +6,13 @@ LL | struct Bar<T = [u8; N], const N: usize>(T); | = note: using type defaults and const parameters in the same parameter list is currently not permitted -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:7:44 | LL | struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U); - | ^ non-trivial anonymous constants must not depend on the parameter `T` + | ^ cannot perform const operation using `T` | - = note: type parameters are currently not permitted in anonymous constants + = note: type parameters may not be used in const expressions error: constant values inside of type parameter defaults must not depend on generic parameters --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21 diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs index b9d74850f37..51f0cff3f21 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.rs @@ -6,7 +6,7 @@ struct Foo<T, U = [u8; std::mem::size_of::<T>()]>(T, U); //[full]~^ ERROR constant values inside of type parameter defaults -//[min]~^^ ERROR generic parameters must not be used inside of non-trivial +//[min]~^^ ERROR generic parameters may not be used in const operations // FIXME(const_generics:defaults): We still don't know how to we deal with type defaults. struct Bar<T = [u8; N], const N: usize>(T); diff --git a/src/test/ui/const-generics/wf-misc.min.stderr b/src/test/ui/const-generics/wf-misc.min.stderr index 1c52d601749..935f12dd2c3 100644 --- a/src/test/ui/const-generics/wf-misc.min.stderr +++ b/src/test/ui/const-generics/wf-misc.min.stderr @@ -1,18 +1,18 @@ -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/wf-misc.rs:9:17 | LL | let _: [u8; N + 1]; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` -error: generic parameters must not be used inside of non-trivial constant values +error: generic parameters may not be used in const operations --> $DIR/wf-misc.rs:17:21 | LL | let _: Const::<{N + 1}>; - | ^ non-trivial anonymous constants must not depend on the parameter `N` + | ^ cannot perform const operation using `N` | - = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + = help: const parameters may only be used as standalone arguments, i.e. `N` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/wf-misc.rs b/src/test/ui/const-generics/wf-misc.rs index f8c41404c46..103c580f28f 100644 --- a/src/test/ui/const-generics/wf-misc.rs +++ b/src/test/ui/const-generics/wf-misc.rs @@ -8,7 +8,7 @@ pub fn arr_len<const N: usize>() { let _: [u8; N + 1]; //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial + //[min]~^^ ERROR generic parameters may not be used in const operations } struct Const<const N: usize>; @@ -16,7 +16,7 @@ struct Const<const N: usize>; pub fn func_call<const N: usize>() { let _: Const::<{N + 1}>; //[full]~^ ERROR constant expression depends on a generic parameter - //[min]~^^ ERROR generic parameters must not be used inside of non-trivial + //[min]~^^ ERROR generic parameters may not be used in const operations } fn main() {} diff --git a/src/test/ui/consts/trait_specialization.stderr b/src/test/ui/consts/trait_specialization.stderr index 03da7d512e5..e80821cf46a 100644 --- a/src/test/ui/consts/trait_specialization.stderr +++ b/src/test/ui/consts/trait_specialization.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.rs b/src/test/ui/did_you_mean/bad-assoc-ty.rs index e66b432ede2..99ebe84cd9d 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.rs +++ b/src/test/ui/did_you_mean/bad-assoc-ty.rs @@ -68,7 +68,6 @@ enum N<F> where F: Fn() -> _ { union O<F> where F: Fn() -> _ { //~^ ERROR the type placeholder `_` is not allowed within types on item signatures -//~| ERROR unions with non-`Copy` fields are unstable foo: F, } diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index 4835d9ab107..ebc0883370b 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -57,19 +57,6 @@ LL | type J = ty!(u8); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0658]: unions with non-`Copy` fields are unstable - --> $DIR/bad-assoc-ty.rs:69:1 - | -LL | / union O<F> where F: Fn() -> _ { -LL | | -LL | | -LL | | foo: F, -LL | | } - | |_^ - | - = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:1:10 | @@ -215,7 +202,7 @@ LL | union O<F, T> where F: Fn() -> T { | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/bad-assoc-ty.rs:75:29 + --> $DIR/bad-assoc-ty.rs:74:29 | LL | trait P<F> where F: Fn() -> _ { | ^ not allowed in type signatures @@ -226,7 +213,7 @@ LL | trait P<F, T> where F: Fn() -> T { | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/bad-assoc-ty.rs:80:38 + --> $DIR/bad-assoc-ty.rs:79:38 | LL | fn foo<F>(_: F) where F: Fn() -> _ {} | ^ not allowed in type signatures @@ -236,7 +223,7 @@ help: use type parameters instead LL | fn foo<F, T>(_: F) where F: Fn() -> T {} | ^^^ ^ -error: aborting due to 29 previous errors +error: aborting due to 28 previous errors -Some errors have detailed explanations: E0121, E0223, E0658. +Some errors have detailed explanations: E0121, E0223. For more information about an error, try `rustc --explain E0121`. diff --git a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr index e1325b789d2..bca493e67d5 100644 --- a/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr +++ b/src/test/ui/did_you_mean/issue-43871-enum-instead-of-variant.stderr @@ -2,7 +2,7 @@ error[E0423]: expected function, tuple struct or tuple variant, found enum `Opti --> $DIR/issue-43871-enum-instead-of-variant.rs:19:13 | LL | let x = Option(1); - | ^^^^^^ help: try using one of the enum's variants: `std::option::Option::Some` + | ^^^^^^ help: try to construct one of the enum's variants: `std::option::Option::Some` | = help: you might have meant to construct the enum's non-tuple variant @@ -10,7 +10,7 @@ error[E0532]: expected tuple struct or tuple variant, found enum `Option` --> $DIR/issue-43871-enum-instead-of-variant.rs:21:12 | LL | if let Option(_) = x { - | ^^^^^^ help: try using one of the enum's variants: `std::option::Option::Some` + | ^^^^^^ help: try to match against one of the enum's variants: `std::option::Option::Some` | = help: you might have meant to match against the enum's non-tuple variant @@ -18,9 +18,14 @@ error[E0532]: expected tuple struct or tuple variant, found enum `Example` --> $DIR/issue-43871-enum-instead-of-variant.rs:27:12 | LL | if let Example(_) = y { - | ^^^^^^^ help: try using one of the enum's variants: `Example::Ex` + | ^^^^^^^ help: try to match against one of the enum's variants: `Example::Ex` | = help: you might have meant to match against the enum's non-tuple variant +note: the enum is defined here + --> $DIR/issue-43871-enum-instead-of-variant.rs:1:1 + | +LL | enum Example { Ex(String), NotEx } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found enum `Void` --> $DIR/issue-43871-enum-instead-of-variant.rs:31:13 @@ -29,6 +34,11 @@ LL | let y = Void(); | ^^^^ | = help: the enum has no tuple variants to construct +note: the enum is defined here + --> $DIR/issue-43871-enum-instead-of-variant.rs:3:1 + | +LL | enum Void {} + | ^^^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found enum `ManyVariants` --> $DIR/issue-43871-enum-instead-of-variant.rs:33:13 @@ -38,6 +48,17 @@ LL | let z = ManyVariants(); | = help: the enum has no tuple variants to construct = help: you might have meant to construct one of the enum's non-tuple variants +note: the enum is defined here + --> $DIR/issue-43871-enum-instead-of-variant.rs:5:1 + | +LL | / enum ManyVariants { +LL | | One, +LL | | Two, +LL | | Three, +... | +LL | | Ten, +LL | | } + | |_^ error: aborting due to 5 previous errors diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index 88d36ab6aa6..b027faa9d7c 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -7,8 +7,6 @@ // edition:2018 // ignore-wasm32-bare compiled with panic=abort by default -#![feature(move_ref_pattern)] - #![allow(unused)] use std::{ diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index d31736f142c..6d0cd101dbc 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -1,8 +1,7 @@ // run-pass // ignore-wasm32-bare compiled with panic=abort by default -#![feature(generators, generator_trait, untagged_unions)] -#![feature(move_ref_pattern)] +#![feature(generators, generator_trait)] #![feature(bindings_after_at)] #![allow(unused_assignments)] diff --git a/src/test/ui/dropck/dropck-union.rs b/src/test/ui/dropck/dropck-union.rs index ef4d1b360b8..5a9965db5ed 100644 --- a/src/test/ui/dropck/dropck-union.rs +++ b/src/test/ui/dropck/dropck-union.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - use std::cell::Cell; use std::ops::Deref; use std::mem::ManuallyDrop; diff --git a/src/test/ui/dropck/dropck-union.stderr b/src/test/ui/dropck/dropck-union.stderr index 228744326f9..854e29385a8 100644 --- a/src/test/ui/dropck/dropck-union.stderr +++ b/src/test/ui/dropck/dropck-union.stderr @@ -1,5 +1,5 @@ error[E0597]: `v` does not live long enough - --> $DIR/dropck-union.rs:39:18 + --> $DIR/dropck-union.rs:37:18 | LL | v.0.set(Some(&v)); | ^^ borrowed value does not live long enough diff --git a/src/test/ui/empty/empty-macro-use.stderr b/src/test/ui/empty/empty-macro-use.stderr index 8e3e06896ee..700f6616af4 100644 --- a/src/test/ui/empty/empty-macro-use.stderr +++ b/src/test/ui/empty/empty-macro-use.stderr @@ -3,6 +3,9 @@ error: cannot find macro `macro_two` in this scope | LL | macro_two!(); | ^^^^^^^^^ + | + = note: consider importing this macro: + two_macros::macro_two error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0007.rs b/src/test/ui/error-codes/E0007.rs deleted file mode 100644 index 022ac5fc113..00000000000 --- a/src/test/ui/error-codes/E0007.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(bindings_after_at)] - -fn main() { - let x = Some("s".to_string()); - match x { - op_string @ Some(s) => {}, - //~^ ERROR E0007 - //~| ERROR E0382 - None => {}, - } -} diff --git a/src/test/ui/error-codes/E0007.stderr b/src/test/ui/error-codes/E0007.stderr deleted file mode 100644 index 89c10516194..00000000000 --- a/src/test/ui/error-codes/E0007.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0007]: cannot bind by-move with sub-bindings - --> $DIR/E0007.rs:6:9 - | -LL | op_string @ Some(s) => {}, - | ^^^^^^^^^^^^^^^^^^^ binds an already bound by-move value by moving it - -error[E0382]: use of moved value - --> $DIR/E0007.rs:6:26 - | -LL | let x = Some("s".to_string()); - | - move occurs because `x` has type `Option<String>`, which does not implement the `Copy` trait -LL | match x { -LL | op_string @ Some(s) => {}, - | -----------------^- - | | | - | | value used here after move - | value moved here - -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0007, E0382. -For more information about an error, try `rustc --explain E0007`. diff --git a/src/test/ui/error-codes/E0060.stderr b/src/test/ui/error-codes/E0060.stderr index a600592c6c2..c80014d1476 100644 --- a/src/test/ui/error-codes/E0060.stderr +++ b/src/test/ui/error-codes/E0060.stderr @@ -1,13 +1,16 @@ error[E0060]: this function takes at least 1 argument but 0 arguments were supplied --> $DIR/E0060.rs:6:14 | -LL | fn printf(_: *const u8, ...) -> u32; - | ------------------------------------ defined here -... LL | unsafe { printf(); } | ^^^^^^-- supplied 0 arguments | | | expected at least 1 argument + | +note: function defined here + --> $DIR/E0060.rs:2:8 + | +LL | fn printf(_: *const u8, ...) -> u32; + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0061.stderr b/src/test/ui/error-codes/E0061.stderr index dfefa0df313..98488a2d298 100644 --- a/src/test/ui/error-codes/E0061.stderr +++ b/src/test/ui/error-codes/E0061.stderr @@ -1,24 +1,30 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/E0061.rs:6:5 | -LL | fn f(a: u16, b: &str) {} - | --------------------- defined here -... LL | f(0); | ^ - supplied 1 argument | | | expected 2 arguments + | +note: function defined here + --> $DIR/E0061.rs:1:4 + | +LL | fn f(a: u16, b: &str) {} + | ^ ------ ------- error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/E0061.rs:10:5 | -LL | fn f2(a: u16) {} - | ------------- defined here -... LL | f2(); | ^^-- supplied 0 arguments | | | expected 1 argument + | +note: function defined here + --> $DIR/E0061.rs:3:4 + | +LL | fn f2(a: u16) {} + | ^^ ------ error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0520.stderr b/src/test/ui/error-codes/E0520.stderr index 1041ccee937..be7b95465a5 100644 --- a/src/test/ui/error-codes/E0520.stderr +++ b/src/test/ui/error-codes/E0520.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0520]: `fly` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/E0520.rs:17:5 diff --git a/src/test/ui/error-codes/E0730.stderr b/src/test/ui/error-codes/E0730.stderr index f915f6edef5..356e4f36042 100644 --- a/src/test/ui/error-codes/E0730.stderr +++ b/src/test/ui/error-codes/E0730.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0730]: cannot pattern-match on an array without a fixed length --> $DIR/E0730.rs:6:9 diff --git a/src/test/ui/error-codes/E0771.stderr b/src/test/ui/error-codes/E0771.stderr index 60220be6b57..b184b599817 100644 --- a/src/test/ui/error-codes/E0771.stderr +++ b/src/test/ui/error-codes/E0771.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error[E0771]: use of non-static lifetime `'a` in const generic --> $DIR/E0771.rs:4:41 diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs index 9ee0e6f681d..f5f9631c3bc 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.rs +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + union U1 { // OK a: u8, } @@ -6,15 +8,23 @@ union U2<T: Copy> { // OK a: T, } -union U3 { //~ ERROR unions with non-`Copy` fields are unstable +union U22<T> { // OK + a: std::mem::ManuallyDrop<T>, +} + +union U3 { a: String, //~ ERROR unions may not contain fields that need dropping } -union U4<T> { //~ ERROR unions with non-`Copy` fields are unstable +union U32 { // field that does not drop but is not `Copy`, either -- this is the real feature gate test! + a: std::cell::RefCell<i32>, //~ ERROR unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable +} + +union U4<T> { a: T, //~ ERROR unions may not contain fields that need dropping } -union U5 { //~ ERROR unions with `Drop` implementations are unstable +union U5 { // Having a drop impl is OK a: u8, } diff --git a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr index 3a123ea1c93..ed973871b3f 100644 --- a/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr +++ b/src/test/ui/feature-gates/feature-gate-untagged_unions.stderr @@ -1,61 +1,37 @@ -error[E0658]: unions with non-`Copy` fields are unstable - --> $DIR/feature-gate-untagged_unions.rs:9:1 +error[E0658]: unions with non-`Copy` fields other than `ManuallyDrop<T>` are unstable + --> $DIR/feature-gate-untagged_unions.rs:20:5 | -LL | / union U3 { -LL | | a: String, -LL | | } - | |_^ - | - = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - -error[E0658]: unions with non-`Copy` fields are unstable - --> $DIR/feature-gate-untagged_unions.rs:13:1 - | -LL | / union U4<T> { -LL | | a: T, -LL | | } - | |_^ - | - = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information - = help: add `#![feature(untagged_unions)]` to the crate attributes to enable - -error[E0658]: unions with `Drop` implementations are unstable - --> $DIR/feature-gate-untagged_unions.rs:17:1 - | -LL | / union U5 { -LL | | a: u8, -LL | | } - | |_^ +LL | a: std::cell::RefCell<i32>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #55149 <https://github.com/rust-lang/rust/issues/55149> for more information = help: add `#![feature(untagged_unions)]` to the crate attributes to enable error[E0740]: unions may not contain fields that need dropping - --> $DIR/feature-gate-untagged_unions.rs:10:5 + --> $DIR/feature-gate-untagged_unions.rs:16:5 | LL | a: String, | ^^^^^^^^^ | note: `std::mem::ManuallyDrop` can be used to wrap the type - --> $DIR/feature-gate-untagged_unions.rs:10:5 + --> $DIR/feature-gate-untagged_unions.rs:16:5 | LL | a: String, | ^^^^^^^^^ error[E0740]: unions may not contain fields that need dropping - --> $DIR/feature-gate-untagged_unions.rs:14:5 + --> $DIR/feature-gate-untagged_unions.rs:24:5 | LL | a: T, | ^^^^ | note: `std::mem::ManuallyDrop` can be used to wrap the type - --> $DIR/feature-gate-untagged_unions.rs:14:5 + --> $DIR/feature-gate-untagged_unions.rs:24:5 | LL | a: T, | ^^^^ -error: aborting due to 5 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0658, E0740. For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr index 16a5ab2cc86..5043a3be91d 100644 --- a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr +++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6]` --> $DIR/generator-yielding-or-returning-itself.rs:15:5 | LL | pub fn want_cyclic_generator_return<T>(_: T) @@ -14,7 +14,7 @@ LL | want_cyclic_generator_return(|| { see issue #46062 <https://github.com/rust-lang/rust/issues/46062> for more information -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6]` --> $DIR/generator-yielding-or-returning-itself.rs:28:5 | LL | pub fn want_cyclic_generator_yield<T>(_: T) diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr index cc45d5631cb..f23949091d9 100644 --- a/src/test/ui/generator/print/generator-print-verbose-2.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr @@ -9,7 +9,7 @@ LL | assert_send(|| { | = help: the trait `Sync` is not implemented for `Cell<i32>` = note: required because of the requirements on the impl of `Send` for `&'_#3r Cell<i32>` - = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#16t]` + = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell<i32>) _#17t]` error: generator cannot be shared between threads safely --> $DIR/generator-print-verbose-2.rs:12:5 diff --git a/src/test/ui/generator/print/generator-print-verbose-3.stderr b/src/test/ui/generator/print/generator-print-verbose-3.stderr index 0ce108dfd62..d15646259b2 100644 --- a/src/test/ui/generator/print/generator-print-verbose-3.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-3.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____^ expected `()`, found generator | = note: expected unit type `()` - found generator `[main::{closure#0} upvar_tys=(unavailable) _#5t]` + found generator `[main::{closure#0} upvar_tys=(unavailable)]` error: aborting due to previous error diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index 216b707bb16..881064d2f84 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -1,11 +1,11 @@ -error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` cannot be unpinned +error[E0277]: `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` cannot be unpinned --> $DIR/static-not-unpin.rs:14:18 | LL | fn assert_unpin<T: Unpin>(_: T) { | ----- required by this bound in `assert_unpin` ... LL | assert_unpin(generator); - | ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6 _]` + | ^^^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/static-not-unpin.rs:11:25: 13:6]` error: aborting due to previous error diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr index 8f6f87f78de..9e111d68a55 100644 --- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -7,7 +7,7 @@ LL | 5 = note: expected type `std::result::Result<{integer}, _>` found type `{integer}` -error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as Generator>::Return == i32` +error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6] as Generator>::Return == i32` --> $DIR/type-mismatch-signature-deduction.rs:5:13 | LL | fn foo() -> impl Generator<Return = i32> { diff --git a/src/test/ui/generator/yielding-in-match-guards.rs b/src/test/ui/generator/yielding-in-match-guards.rs new file mode 100644 index 00000000000..d8aa354b1c6 --- /dev/null +++ b/src/test/ui/generator/yielding-in-match-guards.rs @@ -0,0 +1,24 @@ +// check-pass +// edition:2018 + +// This test is derived from +// https://github.com/rust-lang/rust/issues/72651#issuecomment-668720468 + +// This test demonstrates that, in `async fn g()`, +// indeed a temporary borrow `y` from `x` is live +// while `f().await` is being evaluated. +// Thus, `&'_ u8` should be included in type signature +// of the underlying generator. + +async fn f() -> u8 { 1 } + +pub async fn g(x: u8) { + match x { + y if f().await == y => (), + _ => (), + } +} + +fn main() { + let _ = g(10); +} diff --git a/src/test/ui/glob-resolve1.stderr b/src/test/ui/glob-resolve1.stderr index 3c818f3ae48..cd128c1ea0b 100644 --- a/src/test/ui/glob-resolve1.stderr +++ b/src/test/ui/glob-resolve1.stderr @@ -24,7 +24,17 @@ error[E0423]: expected value, found enum `B` --> $DIR/glob-resolve1.rs:24:5 | LL | B; - | ^ help: try using the enum's variant: `B::B1` + | ^ + | +note: the enum is defined here + --> $DIR/glob-resolve1.rs:12:5 + | +LL | pub enum B { B1 } + | ^^^^^^^^^^^^^^^^^ +help: you might have meant to use the following enum variant + | +LL | B::B1; + | ^^^^^ error[E0425]: cannot find value `C` in this scope --> $DIR/glob-resolve1.rs:25:5 diff --git a/src/test/ui/hrtb/issue-58451.stderr b/src/test/ui/hrtb/issue-58451.stderr index bd08fc1bfae..2cc1c7a2e72 100644 --- a/src/test/ui/hrtb/issue-58451.stderr +++ b/src/test/ui/hrtb/issue-58451.stderr @@ -1,16 +1,16 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/issue-58451.rs:12:9 | -LL | / fn f<I>(i: I) -LL | | where -LL | | I: IntoIterator, -LL | | I::Item: for<'a> Into<&'a ()>, - | |__________________________________- defined here -... -LL | f(&[f()]); - | ^-- supplied 0 arguments - | | - | expected 1 argument +LL | f(&[f()]); + | ^-- supplied 0 arguments + | | + | expected 1 argument + | +note: function defined here + --> $DIR/issue-58451.rs:5:4 + | +LL | fn f<I>(i: I) + | ^ ---- error: aborting due to previous error diff --git a/src/test/ui/hygiene/generic_params.stderr b/src/test/ui/hygiene/generic_params.stderr index 4ca6d199835..6de36deb597 100644 --- a/src/test/ui/hygiene/generic_params.stderr +++ b/src/test/ui/hygiene/generic_params.stderr @@ -6,6 +6,7 @@ LL | #![feature(decl_macro, rustc_attrs, const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/hygiene/issue-61574-const-parameters.stderr b/src/test/ui/hygiene/issue-61574-const-parameters.stderr index b351b8b73a0..3f85383eb33 100644 --- a/src/test/ui/hygiene/issue-61574-const-parameters.stderr +++ b/src/test/ui/hygiene/issue-61574-const-parameters.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr index f31b75238df..02ddc391f6e 100644 --- a/src/test/ui/hygiene/no_implicit_prelude-2018.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude-2018.stderr @@ -3,6 +3,9 @@ error: cannot find macro `print` in this scope | LL | print!(); | ^^^^^ + | + = note: consider importing this macro: + std::print error: aborting due to previous error diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index 3c0c0450774..843dee2478b 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -4,6 +4,9 @@ error: cannot find macro `panic` in this scope LL | assert_eq!(0, 0); | ^^^^^^^^^^^^^^^^^ | + = note: consider importing one of these items: + core::panic + std::panic = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0433]: failed to resolve: use of undeclared type `Vec` diff --git a/src/test/ui/impl-trait/equality-rpass.stderr b/src/test/ui/impl-trait/equality-rpass.stderr index 1abf05dca82..11eeceba0ee 100644 --- a/src/test/ui/impl-trait/equality-rpass.stderr +++ b/src/test/ui/impl-trait/equality-rpass.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index cdaa61ac323..536a4726c6d 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/equality.rs:15:5 diff --git a/src/test/ui/impl-trait/equality2.stderr b/src/test/ui/impl-trait/equality2.stderr index 1780931efc5..1443b76048b 100644 --- a/src/test/ui/impl-trait/equality2.stderr +++ b/src/test/ui/impl-trait/equality2.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/equality2.rs:25:18 diff --git a/src/test/ui/impl-trait/issues/issue-65581.rs b/src/test/ui/impl-trait/issues/issue-65581.rs new file mode 100644 index 00000000000..af65b79d3e8 --- /dev/null +++ b/src/test/ui/impl-trait/issues/issue-65581.rs @@ -0,0 +1,33 @@ +// check-pass + +#![allow(dead_code)] + +trait Trait1<T, U> { + fn f1(self) -> U; +} + +trait Trait2 { + type T; + type U: Trait2<T = Self::T>; + fn f2(f: impl FnOnce(&Self::U)); +} + +fn f3<T: Trait2>() -> impl Trait1<T, T::T> { + Struct1 +} + +struct Struct1; + +impl<T: Trait2> Trait1<T, T::T> for Struct1 { + fn f1(self) -> T::T { + unimplemented!() + } +} + +fn f4<T: Trait2>() { + T::f2(|_| { + f3::<T::U>().f1(); + }); +} + +fn main() {} diff --git a/src/test/ui/issues/issue-18819.stderr b/src/test/ui/issues/issue-18819.stderr index a952c9b46c9..b10d26abe34 100644 --- a/src/test/ui/issues/issue-18819.stderr +++ b/src/test/ui/issues/issue-18819.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/issue-18819.rs:16:5 | -LL | fn print_x(_: &dyn Foo<Item=bool>, extra: &str) { - | ----------------------------------------------- defined here -... LL | print_x(X); | ^^^^^^^ - supplied 1 argument | | | expected 2 arguments + | +note: function defined here + --> $DIR/issue-18819.rs:11:4 + | +LL | fn print_x(_: &dyn Foo<Item=bool>, extra: &str) { + | ^^^^^^^ ---------------------- ----------- error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26094.stderr b/src/test/ui/issues/issue-26094.stderr index 2038d88bf46..a6f1ac9286c 100644 --- a/src/test/ui/issues/issue-26094.stderr +++ b/src/test/ui/issues/issue-26094.stderr @@ -4,11 +4,14 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied LL | $other(None) | ---- supplied 1 argument ... -LL | fn some_function() {} - | ------------------ defined here -... LL | some_macro!(some_function); | ^^^^^^^^^^^^^ expected 0 arguments + | +note: function defined here + --> $DIR/issue-26094.rs:7:4 + | +LL | fn some_function() {} + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35376.stderr b/src/test/ui/issues/issue-35376.stderr index 06c31f3bae0..835277d408e 100644 --- a/src/test/ui/issues/issue-35376.stderr +++ b/src/test/ui/issues/issue-35376.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/issues/issue-4935.stderr b/src/test/ui/issues/issue-4935.stderr index 0cc686e1cf8..03b9b91edef 100644 --- a/src/test/ui/issues/issue-4935.stderr +++ b/src/test/ui/issues/issue-4935.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 1 argument but 2 arguments were supplied --> $DIR/issue-4935.rs:5:13 | -LL | fn foo(a: usize) {} - | ---------------- defined here -LL | LL | fn main() { foo(5, 6) } | ^^^ - - supplied 2 arguments | | | expected 1 argument + | +note: function defined here + --> $DIR/issue-4935.rs:3:4 + | +LL | fn foo(a: usize) {} + | ^^^ -------- error: aborting due to previous error diff --git a/src/test/ui/issues/issue-55380.stderr b/src/test/ui/issues/issue-55380.stderr index 451beebd106..65e94d79670 100644 --- a/src/test/ui/issues/issue-55380.stderr +++ b/src/test/ui/issues/issue-55380.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/issues/issue-59508-1.stderr b/src/test/ui/issues/issue-59508-1.stderr index 5e97339f148..2a4ccda8929 100644 --- a/src/test/ui/issues/issue-59508-1.stderr +++ b/src/test/ui/issues/issue-59508-1.stderr @@ -12,6 +12,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/issues/issue-73427.stderr b/src/test/ui/issues/issue-73427.stderr index 88d19943f02..4b5f65b3461 100644 --- a/src/test/ui/issues/issue-73427.stderr +++ b/src/test/ui/issues/issue-73427.stderr @@ -4,8 +4,18 @@ error[E0423]: expected value, found enum `A` LL | A.foo(); | ^ | - = help: you might have meant to use one of the enum's other variants that have fields -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:1:1 + | +LL | / enum A { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Struct {}, +LL | | Tuple(), +LL | | Unit, +LL | | } + | |_^ +help: you might have meant to use one of the following enum variants | LL | (A::Struct {}).foo(); | ^^^^^^^^^^^^^^ @@ -13,6 +23,12 @@ LL | (A::Tuple()).foo(); | ^^^^^^^^^^^^ LL | A::Unit.foo(); | ^^^^^^^ +help: the following enum variants are available + | +LL | (A::StructWithFields { /* fields */ }).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (A::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `B` --> $DIR/issue-73427.rs:31:5 @@ -20,23 +36,69 @@ error[E0423]: expected value, found enum `B` LL | B.foo(); | ^ | - = help: you might have meant to use one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:9:1 + | +LL | / enum B { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | } + | |_^ +help: the following enum variants are available + | +LL | (B::StructWithFields { /* fields */ }).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (B::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `C` --> $DIR/issue-73427.rs:33:5 | LL | C.foo(); - | ^ help: try using one of the enum's variants: `C::Unit` + | ^ + | +note: the enum is defined here + --> $DIR/issue-73427.rs:14:1 + | +LL | / enum C { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Unit, +LL | | } + | |_^ +help: you might have meant to use the following enum variant + | +LL | C::Unit.foo(); + | ^^^^^^^ +help: the following enum variants are available | - = help: you might have meant to use one of the enum's other variants that have fields +LL | (C::StructWithFields { /* fields */ }).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (C::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `D` --> $DIR/issue-73427.rs:35:5 | LL | D.foo(); - | ^ help: try using one of the enum's variants: `D::Unit` + | ^ + | +note: the enum is defined here + --> $DIR/issue-73427.rs:20:1 + | +LL | / enum D { +LL | | TupleWithFields(()), +LL | | Unit, +LL | | } + | |_^ +help: you might have meant to use the following enum variant | - = help: you might have meant to use the enum's other variant that has fields +LL | D::Unit.foo(); + | ^^^^^^^ +help: the following enum variant is available + | +LL | (D::TupleWithFields(/* fields */)).foo(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected function, tuple struct or tuple variant, found enum `A` --> $DIR/issue-73427.rs:40:13 @@ -45,7 +107,18 @@ LL | let x = A(3); | ^ | = help: you might have meant to construct one of the enum's non-tuple variants -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:1:1 + | +LL | / enum A { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Struct {}, +LL | | Tuple(), +LL | | Unit, +LL | | } + | |_^ +help: try to construct one of the enum's variants | LL | let x = A::TupleWithFields(3); | ^^^^^^^^^^^^^^^^^^ @@ -59,7 +132,18 @@ LL | if let A(3) = x { } | ^ | = help: you might have meant to match against one of the enum's non-tuple variants -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/issue-73427.rs:1:1 + | +LL | / enum A { +LL | | StructWithFields { x: () }, +LL | | TupleWithFields(()), +LL | | Struct {}, +LL | | Tuple(), +LL | | Unit, +LL | | } + | |_^ +help: try to match against one of the enum's variants | LL | if let A::TupleWithFields(3) = x { } | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/lto-opt-level-s.rs b/src/test/ui/lto-opt-level-s.rs new file mode 100644 index 00000000000..a7d9d5024d3 --- /dev/null +++ b/src/test/ui/lto-opt-level-s.rs @@ -0,0 +1,7 @@ +// compile-flags: -Clinker-plugin-lto -Copt-level=s +// build-pass +// no-prefer-dynamic + +#![crate_type = "rlib"] + +pub fn foo() {} diff --git a/src/test/ui/lto-opt-level-z.rs b/src/test/ui/lto-opt-level-z.rs new file mode 100644 index 00000000000..bf1f5e2b263 --- /dev/null +++ b/src/test/ui/lto-opt-level-z.rs @@ -0,0 +1,7 @@ +// compile-flags: -Clinker-plugin-lto -Copt-level=z +// build-pass +// no-prefer-dynamic + +#![crate_type = "rlib"] + +pub fn foo() {} diff --git a/src/test/ui/macros/macro-use-wrong-name.stderr b/src/test/ui/macros/macro-use-wrong-name.stderr index 74fb519cc82..888fb913fb7 100644 --- a/src/test/ui/macros/macro-use-wrong-name.stderr +++ b/src/test/ui/macros/macro-use-wrong-name.stderr @@ -8,6 +8,9 @@ LL | macro_two!(); | LL | macro_rules! macro_one { () => ("one") } | ---------------------- similarly named macro `macro_one` defined here + | + = note: consider importing this macro: + two_macros::macro_two error: aborting due to previous error diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index b0d1bb9823b..60f9eeeca27 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -1,35 +1,44 @@ error[E0061]: this function takes 0 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:13:7 | -LL | fn zero(self) -> Foo { self } - | -------------------- defined here -... LL | x.zero(0) | ^^^^ - supplied 1 argument | | | expected 0 arguments + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:5:8 + | +LL | fn zero(self) -> Foo { self } + | ^^^^ ---- error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:14:7 | -LL | fn one(self, _: isize) -> Foo { self } - | ----------------------------- defined here -... LL | .one() | ^^^- supplied 0 arguments | | | expected 1 argument + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:6:8 + | +LL | fn one(self, _: isize) -> Foo { self } + | ^^^ ---- -------- error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/method-call-err-msg.rs:15:7 | -LL | fn two(self, _: isize, _: isize) -> Foo { self } - | --------------------------------------- defined here -... LL | .two(0); | ^^^ - supplied 1 argument | | | expected 2 arguments + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:7:8 + | +LL | fn two(self, _: isize, _: isize) -> Foo { self } + | ^^^ ---- -------- -------- error[E0599]: no method named `take` found for struct `Foo` in the current scope --> $DIR/method-call-err-msg.rs:19:7 @@ -53,13 +62,16 @@ LL | .take() error[E0061]: this function takes 3 arguments but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:21:7 | -LL | fn three<T>(self, _: T, _: T, _: T) -> Foo { self } - | ------------------------------------------ defined here -... LL | y.three::<usize>(); | ^^^^^--------- supplied 0 arguments | | | expected 3 arguments + | +note: associated function defined here + --> $DIR/method-call-err-msg.rs:8:8 + | +LL | fn three<T>(self, _: T, _: T, _: T) -> Foo { self } + | ^^^^^ ---- ---- ---- ---- error: aborting due to 5 previous errors diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index 63c04bcd7ba..0b1fcf58e2e 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -1,3 +1,11 @@ +error[E0631]: type mismatch in closure arguments + --> $DIR/issue-36053-2.rs:7:32 + | +LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); + | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _` + | | + | expected signature of `for<'r> fn(&'r &str) -> _` + error[E0599]: no method named `count` found for struct `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope --> $DIR/issue-36053-2.rs:7:55 | @@ -20,14 +28,6 @@ LL | pub struct Filter<I, P> { `Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` which is required by `&mut Filter<Fuse<std::iter::Once<&str>>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` -error[E0631]: type mismatch in closure arguments - --> $DIR/issue-36053-2.rs:7:32 - | -LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | ^^^^^^ -------------- found signature of `for<'r> fn(&'r str) -> _` - | | - | expected signature of `for<'r> fn(&'r &str) -> _` - error: aborting due to 2 previous errors Some errors have detailed explanations: E0599, E0631. diff --git a/src/test/ui/mismatched_types/issue-38371.stderr b/src/test/ui/mismatched_types/issue-38371.stderr index c2bce305877..5d2ce9302ec 100644 --- a/src/test/ui/mismatched_types/issue-38371.stderr +++ b/src/test/ui/mismatched_types/issue-38371.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-38371.rs:4:8 | LL | fn foo(&foo: Foo) { - | ^^^^------ + | ^^^^----- | | | | | expected due to this | expected struct `Foo`, found reference diff --git a/src/test/ui/missing/missing-macro-use.stderr b/src/test/ui/missing/missing-macro-use.stderr index 711e249d2bc..ced062269df 100644 --- a/src/test/ui/missing/missing-macro-use.stderr +++ b/src/test/ui/missing/missing-macro-use.stderr @@ -3,6 +3,9 @@ error: cannot find macro `macro_two` in this scope | LL | macro_two!(); | ^^^^^^^^^ + | + = note: consider importing this macro: + two_macros::macro_two error: aborting due to previous error diff --git a/src/test/ui/not-enough-arguments.rs b/src/test/ui/not-enough-arguments.rs index 631bb1dd274..42476255188 100644 --- a/src/test/ui/not-enough-arguments.rs +++ b/src/test/ui/not-enough-arguments.rs @@ -6,7 +6,26 @@ fn foo(a: isize, b: isize, c: isize, d:isize) { panic!(); } +// Check that all arguments are shown in the error message, even if they're across multiple lines. +fn bar( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, +) { + println!("{}", a); + println!("{}", b); + println!("{}", c); + println!("{}", d); + println!("{}", e); + println!("{}", f); +} + fn main() { foo(1, 2, 3); //~^ ERROR this function takes 4 arguments but 3 + bar(1, 2, 3); + //~^ ERROR this function takes 6 arguments but 3 } diff --git a/src/test/ui/not-enough-arguments.stderr b/src/test/ui/not-enough-arguments.stderr index f2b57f71400..df957837241 100644 --- a/src/test/ui/not-enough-arguments.stderr +++ b/src/test/ui/not-enough-arguments.stderr @@ -1,14 +1,43 @@ error[E0061]: this function takes 4 arguments but 3 arguments were supplied - --> $DIR/not-enough-arguments.rs:10:3 + --> $DIR/not-enough-arguments.rs:27:3 | -LL | fn foo(a: isize, b: isize, c: isize, d:isize) { - | --------------------------------------------- defined here -... LL | foo(1, 2, 3); | ^^^ - - - supplied 3 arguments | | | expected 4 arguments + | +note: function defined here + --> $DIR/not-enough-arguments.rs:5:4 + | +LL | fn foo(a: isize, b: isize, c: isize, d:isize) { + | ^^^ -------- -------- -------- ------- + +error[E0061]: this function takes 6 arguments but 3 arguments were supplied + --> $DIR/not-enough-arguments.rs:29:3 + | +LL | bar(1, 2, 3); + | ^^^ - - - supplied 3 arguments + | | + | expected 6 arguments + | +note: function defined here + --> $DIR/not-enough-arguments.rs:10:4 + | +LL | fn bar( + | ^^^ +LL | a: i32, + | ------ +LL | b: i32, + | ------ +LL | c: i32, + | ------ +LL | d: i32, + | ------ +LL | e: i32, + | ------ +LL | f: i32, + | ------ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0061`. diff --git a/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr b/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr index 16df31ba2a8..fca98662708 100644 --- a/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr +++ b/src/test/ui/overlap-doesnt-conflict-with-specialization.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/parser/assoc-static-semantic-fail.stderr b/src/test/ui/parser/assoc-static-semantic-fail.stderr index bc3054c3e30..7ae092cee67 100644 --- a/src/test/ui/parser/assoc-static-semantic-fail.stderr +++ b/src/test/ui/parser/assoc-static-semantic-fail.stderr @@ -170,6 +170,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error: aborting due to 24 previous errors; 1 warning emitted diff --git a/src/test/ui/parser/default.stderr b/src/test/ui/parser/default.stderr index dea35666f37..5b763ae72f5 100644 --- a/src/test/ui/parser/default.stderr +++ b/src/test/ui/parser/default.stderr @@ -31,6 +31,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0046]: not all trait items implemented, missing: `foo` --> $DIR/default.rs:22:1 diff --git a/src/test/ui/parser/float-field.stderr b/src/test/ui/parser/float-field.stderr index 62202b99964..7090efc5014 100644 --- a/src/test/ui/parser/float-field.stderr +++ b/src/test/ui/parser/float-field.stderr @@ -271,10 +271,10 @@ LL | s.1e1; = note: available fields are: `0`, `1` error[E0609]: no field `1e1` on type `(u8, u8)` - --> $DIR/float-field.rs:9:7 + --> $DIR/float-field.rs:9:9 | LL | s.1.1e1; - | ^^^^^ + | ^^^ error[E0609]: no field `0x1e1` on type `S` --> $DIR/float-field.rs:24:7 @@ -288,7 +288,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:25:7 | LL | s.0x1.; - | ^^^^ unknown field + | ^^^ unknown field | = note: available fields are: `0`, `1` @@ -296,7 +296,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:28:7 | LL | s.0x1.1; - | ^^^^^ unknown field + | ^^^ unknown field | = note: available fields are: `0`, `1` @@ -304,7 +304,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:30:7 | LL | s.0x1.1e1; - | ^^^^^^^ unknown field + | ^^^ unknown field | = note: available fields are: `0`, `1` diff --git a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr index e8ff93f6323..cdc9ee8d9e7 100644 --- a/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr +++ b/src/test/ui/parser/trait-item-with-defaultness-fail-semantic.stderr @@ -54,6 +54,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error: aborting due to 6 previous errors; 1 warning emitted diff --git a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr index 21992a29670..3f3ddfed14a 100644 --- a/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr +++ b/src/test/ui/parser/variadic-ffi-semantic-restrictions.stderr @@ -2,205 +2,205 @@ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:5:19 | LL | fn f1_1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9 | LL | fn f1_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:8:9 | LL | fn f1_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:12:30 | LL | extern "C" fn f2_1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:15:20 | LL | extern "C" fn f2_2(...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20 | LL | extern "C" fn f2_3(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:19:20 | LL | extern "C" fn f2_3(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:23:26 | LL | extern fn f3_1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16 | LL | extern fn f3_2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:26:16 | LL | extern fn f3_2(...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16 | LL | extern fn f3_3(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:30:16 | LL | extern fn f3_3(..., x: isize) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:35:13 | LL | fn e_f1(...); - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:37:13 | LL | fn e_f2(..., x: isize); - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:44:23 | LL | fn i_f1(x: isize, ...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13 | LL | fn i_f2(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:46:13 | LL | fn i_f2(...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13 | LL | fn i_f3(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:49:13 | LL | fn i_f3(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:49:28 | LL | fn i_f3(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13 | LL | fn i_f4(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:53:13 | LL | fn i_f4(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:53:28 | LL | fn i_f4(..., x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:60:23 | LL | fn t_f1(x: isize, ...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:62:23 | LL | fn t_f2(x: isize, ...); - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13 | LL | fn t_f3(...) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:64:13 | LL | fn t_f3(...) {} - | ^^^^ + | ^^^ error: C-variadic function must be declared with at least one named argument --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13 | LL | fn t_f4(...); - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:67:13 | LL | fn t_f4(...); - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13 | LL | fn t_f5(..., x: isize) {} - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:70:13 | LL | fn t_f5(..., x: isize) {} - | ^^^^ + | ^^^ error: `...` must be the last argument of a C-variadic function --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13 | LL | fn t_f6(..., x: isize); - | ^^^^ + | ^^^ error: only foreign or `unsafe extern "C" functions may be C-variadic --> $DIR/variadic-ffi-semantic-restrictions.rs:73:13 | LL | fn t_f6(..., x: isize); - | ^^^^ + | ^^^ error: aborting due to 34 previous errors diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs index c00296c34c4..ba9543bf738 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.rs @@ -3,7 +3,6 @@ // where one side is by-ref and the other is by-move. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] struct X { x: (), diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr index 8a6ea8e91a2..44dbcb9a754 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:15:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:14:14 | LL | Some(ref _y @ _z) => {} | ------^^^-- @@ -8,7 +8,7 @@ LL | Some(ref _y @ _z) => {} | value borrowed, by `_y`, here error: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:14 | LL | Some(_z @ ref _y) => {} | --^^^------ @@ -18,7 +18,7 @@ LL | Some(_z @ ref _y) => {} | move occurs because `_z` has type `X` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:29:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:28:14 | LL | Some(ref mut _y @ _z) => {} | ----------^^^-- @@ -27,7 +27,7 @@ LL | Some(ref mut _y @ _z) => {} | value borrowed, by `_y`, here error: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:14 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:14 | LL | Some(_z @ ref mut _y) => {} | --^^^---------- @@ -37,7 +37,7 @@ LL | Some(_z @ ref mut _y) => {} | move occurs because `_z` has type `X` which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:21:19 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:20:19 | LL | Some(_z @ ref _y) => {} | -----^^^^^^ @@ -52,7 +52,7 @@ LL | Some(ref _z @ ref _y) => {} | ^^^ error[E0382]: borrow of moved value - --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:35:19 + --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:34:19 | LL | Some(_z @ ref mut _y) => {} | -----^^^^^^^^^^ diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs index 7a2e5128b85..3ab6f40725c 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.rs @@ -1,7 +1,6 @@ // See issue #12534. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() {} diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr index cfd978e1327..f25d5a2d9b8 100644 --- a/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr +++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-no-subbindings-fun-param.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/bind-by-move-no-subbindings-fun-param.rs:10:12 + --> $DIR/bind-by-move-no-subbindings-fun-param.rs:9:12 | LL | fn f(a @ A(u): A) -> Box<u8> { | ------^- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs index 10865b92393..d014c9828da 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.rs @@ -1,7 +1,6 @@ // Test that moving on both sides of an `@` pattern is not allowed. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; // Not copy! diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr index d28edd11e12..5039f580ff6 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:14:13 + --> $DIR/borrowck-move-and-move.rs:13:13 | LL | let a @ b = U; | ----^ - move occurs because value has type `U`, which does not implement the `Copy` trait @@ -8,7 +8,7 @@ LL | let a @ b = U; | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:16:17 + --> $DIR/borrowck-move-and-move.rs:15:17 | LL | let a @ (b, c) = (U, U); | --------^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -17,7 +17,7 @@ LL | let a @ (b, c) = (U, U); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:18:17 + --> $DIR/borrowck-move-and-move.rs:17:17 | LL | let a @ (b, c) = (u(), u()); | --------^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -26,7 +26,7 @@ LL | let a @ (b, c) = (u(), u()); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:21:16 + --> $DIR/borrowck-move-and-move.rs:20:16 | LL | match Ok(U) { | ----- move occurs because value has type `std::result::Result<U, U>`, which does not implement the `Copy` trait @@ -37,7 +37,7 @@ LL | a @ Ok(b) | a @ Err(b) => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:21:29 + --> $DIR/borrowck-move-and-move.rs:20:29 | LL | match Ok(U) { | ----- move occurs because value has type `std::result::Result<U, U>`, which does not implement the `Copy` trait @@ -48,7 +48,7 @@ LL | a @ Ok(b) | a @ Err(b) => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:28:22 + --> $DIR/borrowck-move-and-move.rs:27:22 | LL | match [u(), u(), u(), u()] { | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait @@ -59,7 +59,7 @@ LL | xs @ [a, .., b] => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:32:18 + --> $DIR/borrowck-move-and-move.rs:31:18 | LL | match [u(), u(), u(), u()] { | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait @@ -70,7 +70,7 @@ LL | xs @ [_, ys @ .., _] => {} | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-move-and-move.rs:25:16 + --> $DIR/borrowck-move-and-move.rs:24:16 | LL | fn fun(a @ b: U) {} | ----^ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs index 271f4bca0fc..f1ee87bc9c6 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs @@ -3,7 +3,6 @@ // Test `@` patterns combined with `box` patterns. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] #![feature(box_patterns)] #[derive(Copy, Clone)] diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs index f1680e9e888..236710ed854 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.rs @@ -1,7 +1,6 @@ // Test `@` patterns combined with `box` patterns. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] #![feature(box_patterns)] #[derive(Copy, Clone)] diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr index 44888369ab2..d9a8bbfb6b1 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-at-and-box.rs:37:9 + --> $DIR/borrowck-pat-at-and-box.rs:36:9 | LL | let ref a @ box b = Box::new(NC); | -----^^^^^^^- @@ -8,7 +8,7 @@ LL | let ref a @ box b = Box::new(NC); | value borrowed, by `a`, here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:39:9 + --> $DIR/borrowck-pat-at-and-box.rs:38:9 | LL | let ref a @ box ref mut b = Box::new(nc()); | -----^^^^^^^--------- @@ -17,7 +17,7 @@ LL | let ref a @ box ref mut b = Box::new(nc()); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:41:9 + --> $DIR/borrowck-pat-at-and-box.rs:40:9 | LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- @@ -26,7 +26,7 @@ LL | let ref a @ box ref mut b = Box::new(NC); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:43:9 + --> $DIR/borrowck-pat-at-and-box.rs:42:9 | LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- @@ -35,7 +35,7 @@ LL | let ref a @ box ref mut b = Box::new(NC); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:46:9 + --> $DIR/borrowck-pat-at-and-box.rs:45:9 | LL | let ref a @ box ref mut b = Box::new(NC); | -----^^^^^^^--------- @@ -44,7 +44,7 @@ LL | let ref a @ box ref mut b = Box::new(NC); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:52:9 + --> $DIR/borrowck-pat-at-and-box.rs:51:9 | LL | let ref mut a @ box ref b = Box::new(NC); | ---------^^^^^^^----- @@ -53,7 +53,7 @@ LL | let ref mut a @ box ref b = Box::new(NC); | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:66:9 + --> $DIR/borrowck-pat-at-and-box.rs:65:9 | LL | ref mut a @ box ref b => { | ---------^^^^^^^----- @@ -62,7 +62,7 @@ LL | ref mut a @ box ref b => { | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:58:11 + --> $DIR/borrowck-pat-at-and-box.rs:57:11 | LL | fn f5(ref mut a @ box ref b: Box<NC>) { | ---------^^^^^^^----- @@ -71,7 +71,7 @@ LL | fn f5(ref mut a @ box ref b: Box<NC>) { | mutable borrow, by `a`, occurs here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:21:18 + --> $DIR/borrowck-pat-at-and-box.rs:20:18 | LL | let a @ box &b = Box::new(&C); | ---------^ ------------ move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait @@ -80,7 +80,7 @@ LL | let a @ box &b = Box::new(&C); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:24:17 + --> $DIR/borrowck-pat-at-and-box.rs:23:17 | LL | let a @ box b = Box::new(C); | --------^ ----------- move occurs because value has type `Box<C>`, which does not implement the `Copy` trait @@ -89,7 +89,7 @@ LL | let a @ box b = Box::new(C); | value moved here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:34:17 + --> $DIR/borrowck-pat-at-and-box.rs:33:17 | LL | match Box::new(C) { | ----------- move occurs because value has type `Box<C>`, which does not implement the `Copy` trait @@ -100,7 +100,7 @@ LL | a @ box b => {} | value moved here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-at-and-box.rs:46:21 + --> $DIR/borrowck-pat-at-and-box.rs:45:21 | LL | let ref a @ box ref mut b = Box::new(NC); | ------------^^^^^^^^^ @@ -112,7 +112,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:52:25 + --> $DIR/borrowck-pat-at-and-box.rs:51:25 | LL | let ref mut a @ box ref b = Box::new(NC); | ----------------^^^^^ @@ -124,7 +124,7 @@ LL | *a = Box::new(NC); | -- mutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:66:25 + --> $DIR/borrowck-pat-at-and-box.rs:65:25 | LL | ref mut a @ box ref b => { | ----------------^^^^^ @@ -136,7 +136,7 @@ LL | *a = Box::new(NC); | -- mutable borrow later used here error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:27:20 + --> $DIR/borrowck-pat-at-and-box.rs:26:20 | LL | fn f1(a @ box &b: Box<&C>) {} | ---------^ @@ -146,7 +146,7 @@ LL | fn f1(a @ box &b: Box<&C>) {} | move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-at-and-box.rs:30:19 + --> $DIR/borrowck-pat-at-and-box.rs:29:19 | LL | fn f2(a @ box b: Box<C>) {} | --------^ @@ -156,7 +156,7 @@ LL | fn f2(a @ box b: Box<C>) {} | move occurs because value has type `Box<C>`, which does not implement the `Copy` trait error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-at-and-box.rs:58:27 + --> $DIR/borrowck-pat-at-and-box.rs:57:27 | LL | fn f5(ref mut a @ box ref b: Box<NC>) { | ----------------^^^^^ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs index 993954b450e..a22d27763d2 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.rs @@ -2,7 +2,6 @@ // Currently this logic exists in THIR match checking as opposed to borrowck. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr index dacf23f9ded..0e09d478e3a 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr @@ -1,5 +1,5 @@ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:9:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse-promotion.rs:8:9 | LL | let a @ ref b = U; | -^^^----- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs index 7d9618c8df7..3e5a543c4c3 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.rs @@ -1,7 +1,6 @@ // Test that `by_move_binding @ pat_with_by_ref_bindings` is prevented. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index 86e09e55585..282031aeb07 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -1,5 +1,5 @@ error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:28:9 | LL | let a @ ref b = U; | -^^^----- @@ -9,7 +9,7 @@ LL | let a @ ref b = U; | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | -^^^^^^^^^^^^---------^^^^^^-----^ @@ -20,7 +20,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:14 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:14 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | -----^^^--------- @@ -30,7 +30,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | -^^^----- @@ -40,7 +40,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:9 | LL | let a @ [ref mut b, ref c] = [U, U]; | -^^^^---------^^-----^ @@ -51,7 +51,7 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:9 | LL | let a @ ref b = u(); | -^^^----- @@ -61,7 +61,7 @@ LL | let a @ ref b = u(); | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:9 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | -^^^^^^^^^^^^---------^^^^^^-----^ @@ -72,7 +72,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:14 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:14 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | -----^^^--------- @@ -82,7 +82,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | -^^^----- @@ -92,7 +92,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:9 | LL | let a @ [ref mut b, ref c] = [u(), u()]; | -^^^^---------^^-----^ @@ -103,7 +103,7 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:56:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9 | LL | a @ Some(ref b) => {} | -^^^^^^^^-----^ @@ -113,7 +113,7 @@ LL | a @ Some(ref b) => {} | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:9 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ @@ -124,7 +124,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:19 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:19 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----^^^--------- @@ -134,7 +134,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^----- @@ -144,7 +144,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:9 | LL | mut a @ Some([ref b, ref mut c]) => {} | -----^^^^^^^^^-----^^---------^^ @@ -155,7 +155,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:9 | LL | a @ Some(ref b) => {} | -^^^^^^^^-----^ @@ -165,7 +165,7 @@ LL | a @ Some(ref b) => {} | move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:9 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^^^^^^^^^^^^^^^---------^^^^^^-----^^ @@ -176,7 +176,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:19 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:19 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----^^^--------- @@ -186,7 +186,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -^^^----- @@ -196,7 +196,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:9 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:9 | LL | mut a @ Some([ref b, ref mut c]) => {} | -----^^^^^^^^^-----^^---------^^ @@ -207,7 +207,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:11 | LL | fn f1(a @ ref b: U) {} | -^^^----- @@ -217,7 +217,7 @@ LL | fn f1(a @ ref b: U) {} | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:11 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:11 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | -----^^^^^^^^-----^^^^^^^^^^-----^ @@ -228,7 +228,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:20 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:20 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | -^^^----- @@ -238,7 +238,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | -----^^^----- @@ -248,7 +248,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:11 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:11 | LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | -^^^^---------^^-----^ @@ -259,7 +259,7 @@ LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:22 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:22 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | --------^^^^^^^^^ @@ -270,7 +270,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | ------------------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -279,7 +279,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:37 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:30:37 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | ----^^^^^ @@ -290,7 +290,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:25 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:37:25 | LL | let a @ [ref mut b, ref c] = [U, U]; | ----------------^^^^^- ------ move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait @@ -299,7 +299,7 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:13 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:40:13 | LL | let a @ ref b = u(); | ----^^^^^ --- move occurs because value has type `U`, which does not implement the `Copy` trait @@ -308,7 +308,7 @@ LL | let a @ ref b = u(); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:22 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:22 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | --------^^^^^^^^^ @@ -319,7 +319,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | ------------------------^^^^^^^^^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -328,7 +328,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:37 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:43:37 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | ----^^^^^ @@ -339,7 +339,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:25 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:50:25 | LL | let a @ [ref mut b, ref c] = [u(), u()]; | ----------------^^^^^- ---------- move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait @@ -348,7 +348,7 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:27 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:27 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | --------^^^^^^^^^ @@ -363,7 +363,7 @@ LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} | ^^^ error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:38 | LL | match Some((U, U)) { | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait @@ -374,7 +374,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:42 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:60:42 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | ----^^^^^ @@ -389,7 +389,7 @@ LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} | ^^^ error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:70:30 | LL | match Some([U, U]) { | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait @@ -400,7 +400,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:18 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:76:18 | LL | match Some(u()) { | --------- move occurs because value has type `Option<U>`, which does not implement the `Copy` trait @@ -411,7 +411,7 @@ LL | a @ Some(ref b) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:27 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:27 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | --------^^^^^^^^^ @@ -426,7 +426,7 @@ LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} | ^^^ error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:38 | LL | match Some((u(), u())) { | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait @@ -437,7 +437,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:42 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:82:42 | LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | ----^^^^^ @@ -452,7 +452,7 @@ LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} | ^^^ error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:92:30 | LL | match Some([u(), u()]) { | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait @@ -463,7 +463,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:15 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:13:15 | LL | fn f1(a @ ref b: U) {} | ----^^^^^ @@ -473,7 +473,7 @@ LL | fn f1(a @ ref b: U) {} | move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:24 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:24 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | ----^^^^^ @@ -484,7 +484,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:31 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | --------------------^^^^^^^^^^^^^- @@ -494,7 +494,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | move occurs because value has type `(U, U)`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:39 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:17:39 | LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | --------^^^^^ @@ -505,7 +505,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:27 + --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:27 | LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | ----------------^^^^^- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs index b7c8c8766c0..42c3290ddfb 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.rs @@ -1,7 +1,6 @@ // Test that `ref mut? @ pat_with_by_move_bindings` is prevented. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr index e5419efa00b..a275705b193 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:23:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:22:9 | LL | let ref a @ b = U; | -----^^^- @@ -8,7 +8,7 @@ LL | let ref a @ b = U; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:25:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:9 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ @@ -18,7 +18,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:25:18 + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:18 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^----- @@ -27,7 +27,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:25:33 + --> $DIR/borrowck-pat-by-move-and-ref.rs:24:33 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | -----^^^- @@ -36,7 +36,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (U, U); | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:29:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:28:9 | LL | let ref mut a @ [b, mut c] = [U, U]; | ---------^^^^-^^-----^ @@ -46,7 +46,7 @@ LL | let ref mut a @ [b, mut c] = [U, U]; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:31:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:30:9 | LL | let ref a @ b = u(); | -----^^^- @@ -55,7 +55,7 @@ LL | let ref a @ b = u(); | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:32:9 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ @@ -65,7 +65,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:33:18 + --> $DIR/borrowck-pat-by-move-and-ref.rs:32:18 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^----- @@ -74,7 +74,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:33:33 + --> $DIR/borrowck-pat-by-move-and-ref.rs:32:33 | LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | -----^^^- @@ -83,7 +83,7 @@ LL | let ref a @ (ref b @ mut c, ref d @ e) = (u(), u()); | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:37:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:36:9 | LL | let ref mut a @ [b, mut c] = [u(), u()]; | ---------^^^^-^^-----^ @@ -93,7 +93,7 @@ LL | let ref mut a @ [b, mut c] = [u(), u()]; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:41:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:40:9 | LL | ref a @ Some(b) => {} | -----^^^^^^^^-^ @@ -102,7 +102,7 @@ LL | ref a @ Some(b) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:46:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:45:9 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ @@ -112,7 +112,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:46:23 + --> $DIR/borrowck-pat-by-move-and-ref.rs:45:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^----- @@ -121,7 +121,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:46:38 + --> $DIR/borrowck-pat-by-move-and-ref.rs:45:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^- @@ -130,7 +130,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:53:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:52:9 | LL | ref mut a @ Some([b, mut c]) => {} | ---------^^^^^^^^^-^^-----^^ @@ -140,7 +140,7 @@ LL | ref mut a @ Some([b, mut c]) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:58:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:57:9 | LL | ref a @ Some(b) => {} | -----^^^^^^^^-^ @@ -149,7 +149,7 @@ LL | ref a @ Some(b) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:63:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:62:9 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^^^^^^^^^^^^^^^-----^^^^^^^^^^-^^ @@ -159,7 +159,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:63:23 + --> $DIR/borrowck-pat-by-move-and-ref.rs:62:23 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^----- @@ -168,7 +168,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:63:38 + --> $DIR/borrowck-pat-by-move-and-ref.rs:62:38 | LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | -----^^^- @@ -177,7 +177,7 @@ LL | ref a @ Some((ref b @ mut c, ref d @ e)) => {} | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:70:9 + --> $DIR/borrowck-pat-by-move-and-ref.rs:69:9 | LL | ref mut a @ Some([b, mut c]) => {} | ---------^^^^^^^^^-^^-----^^ @@ -187,7 +187,7 @@ LL | ref mut a @ Some([b, mut c]) => {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:14:11 + --> $DIR/borrowck-pat-by-move-and-ref.rs:13:11 | LL | fn f1(ref a @ b: U) {} | -----^^^- @@ -196,7 +196,7 @@ LL | fn f1(ref a @ b: U) {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:16:11 + --> $DIR/borrowck-pat-by-move-and-ref.rs:15:11 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^^^^^^^^^^-----^^^^^^^^^^-^ @@ -206,7 +206,7 @@ LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:16:20 + --> $DIR/borrowck-pat-by-move-and-ref.rs:15:20 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^----- @@ -215,7 +215,7 @@ LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | value borrowed, by `b`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:16:35 + --> $DIR/borrowck-pat-by-move-and-ref.rs:15:35 | LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | -----^^^- @@ -224,7 +224,7 @@ LL | fn f2(ref a @ (ref b @ mut c, ref d @ e): (U, U)) {} | value borrowed, by `d`, here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-by-move-and-ref.rs:20:11 + --> $DIR/borrowck-pat-by-move-and-ref.rs:19:11 | LL | fn f3(ref mut a @ [b, mut c]: [U; 2]) {} | ---------^^^^-^^-----^ diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs index 2b5e339c639..f67cd45ca95 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.rs @@ -1,5 +1,4 @@ #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] enum Option<T> { None, diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index 695da9639af..e6231dd49ba 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:9 | LL | ref mut z @ &mut Some(ref a) => { | ---------^^^^^^^^^^^^^-----^ @@ -8,7 +8,7 @@ LL | ref mut z @ &mut Some(ref a) => { | mutable borrow, by `z`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:9 | LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | ---------^^^^-----------------^ @@ -18,7 +18,7 @@ LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:35:22 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:34:22 | LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | -----^^^--------- @@ -27,7 +27,7 @@ LL | let ref mut a @ (ref b @ ref mut c) = u(); // sub-in-sub | immutable borrow, by `b`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:39:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:38:9 | LL | let ref a @ ref mut b = U; | -----^^^--------- @@ -36,7 +36,7 @@ LL | let ref a @ ref mut b = U; | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:41:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:40:9 | LL | let ref mut a @ ref b = U; | ---------^^^----- @@ -45,7 +45,7 @@ LL | let ref mut a @ ref b = U; | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:43:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:42:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -55,7 +55,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:45:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:44:9 | LL | let ref mut a @ (ref b, ref c) = (U, U); | ---------^^^^-----^^-----^ @@ -65,7 +65,7 @@ LL | let ref mut a @ (ref b, ref c) = (U, U); | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:9 | LL | let ref mut a @ ref b = u(); | ---------^^^----- @@ -74,7 +74,7 @@ LL | let ref mut a @ ref b = u(); | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:9 | LL | let ref a @ ref mut b = u(); | -----^^^--------- @@ -83,7 +83,7 @@ LL | let ref a @ ref mut b = u(); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:59:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:58:9 | LL | let ref mut a @ ref b = U; | ---------^^^----- @@ -92,7 +92,7 @@ LL | let ref mut a @ ref b = U; | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:63:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:62:9 | LL | let ref a @ ref mut b = U; | -----^^^--------- @@ -101,7 +101,7 @@ LL | let ref a @ ref mut b = U; | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | ---------^^^^^^-----^ @@ -110,7 +110,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:69:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:68:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | ---------^^^^^^^-----^ @@ -119,7 +119,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) => { | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----^^^^^^---------^ @@ -128,7 +128,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----^^^^^^^---------^ @@ -137,7 +137,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | -----^^^^^^---------^ @@ -146,7 +146,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | -----^^^^^^^---------^ @@ -155,7 +155,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ---------^^^^^^-----^ @@ -164,7 +164,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ---------^^^^^^^-----^ @@ -173,7 +173,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:9 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | -----^^^^^^---------^ @@ -182,7 +182,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:33 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | -----^^^^^^^---------^ @@ -191,7 +191,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:9 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ---------^^^^^^-----^ @@ -200,7 +200,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false | mutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:33 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:33 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ---------^^^^^^^-----^ @@ -209,7 +209,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:119:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:118:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -219,7 +219,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -229,7 +229,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:9 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | -----^^^^---------^^---------^ @@ -239,7 +239,7 @@ LL | let ref a @ (ref mut b, ref mut c) = (U, U); | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:136:9 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:135:9 | LL | let ref mut a @ (ref b, ref c) = (U, U); | ---------^^^^-----^^-----^ @@ -249,7 +249,7 @@ LL | let ref mut a @ (ref b, ref c) = (U, U); | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:25:11 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:24:11 | LL | fn f1(ref a @ ref mut b: U) {} | -----^^^--------- @@ -258,7 +258,7 @@ LL | fn f1(ref a @ ref mut b: U) {} | immutable borrow, by `a`, occurs here error: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:27:11 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:26:11 | LL | fn f2(ref mut a @ ref b: U) {} | ---------^^^----- @@ -267,7 +267,7 @@ LL | fn f2(ref mut a @ ref b: U) {} | mutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:29:11 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:28:11 | LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} | -----^^^^^^^^^^^----------------^^^^^^^^ @@ -276,7 +276,7 @@ LL | fn f3(ref a @ [ref b, ref mut mid @ .., ref c]: [U; 4]) {} | immutable borrow, by `a`, occurs here error: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:22 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:22 | LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | -----^^^------------- @@ -286,7 +286,7 @@ LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | immutable borrow, by `a`, occurs here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:31:30 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:30:30 | LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | ---------^^^- @@ -295,7 +295,7 @@ LL | fn f4_also_moved(ref a @ ref mut b @ c: U) {} | value borrowed, by `b`, here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:11:31 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:10:31 | LL | ref mut z @ &mut Some(ref a) => { | ----------------------^^^^^- @@ -307,7 +307,7 @@ LL | **z = None; | ---------- mutable borrow later used here error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:48:21 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:47:21 | LL | let ref mut a @ ref b = u(); | ------------^^^^^ @@ -319,7 +319,7 @@ LL | *a = u(); | -------- mutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:53:17 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:52:17 | LL | let ref a @ ref mut b = u(); | --------^^^^^^^^^ @@ -331,7 +331,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:20 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:20 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | -----------^^^^^^^^^- @@ -343,7 +343,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:78:45 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:77:45 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) => { | ------------^^^^^^^^^- @@ -355,7 +355,7 @@ LL | drop(a); | - immutable borrow later used here error[E0594]: cannot assign to `*b`, as it is immutable for the pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:89:61 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:88:61 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } => {} | ^^^^^^ cannot assign @@ -363,7 +363,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { *b = U; false } = note: variables bound in patterns are immutable until the end of the pattern guard error[E0594]: cannot assign to `*a`, as it is immutable for the pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:96:61 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:95:61 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); false } => {} | ^^^^^^^^^^^ cannot assign @@ -371,7 +371,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { *a = Err(U); fa = note: variables bound in patterns are immutable until the end of the pattern guard error[E0507]: cannot move out of `b` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait @@ -379,7 +379,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `b` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:102:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait @@ -387,7 +387,7 @@ LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `a` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^ move occurs because `a` has type `&mut std::result::Result<U, U>`, which does not implement the `Copy` trait @@ -395,7 +395,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0507]: cannot move out of `a` in pattern guard - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:110:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} | ^ move occurs because `a` has type `&mut std::result::Result<U, U>`, which does not implement the `Copy` trait @@ -403,7 +403,7 @@ LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false = note: variables bound in patterns cannot be moved from until after the end of the pattern guard error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:18 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:18 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ---------^^^^^^^^^------------ @@ -415,7 +415,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:124:29 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:123:29 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | --------------------^^^^^^^^^- @@ -427,7 +427,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:18 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:18 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | ---------^^^^^^^^^------------ @@ -439,7 +439,7 @@ LL | drop(a); | - immutable borrow later used here error[E0502]: cannot borrow value as mutable because it is also borrowed as immutable - --> $DIR/borrowck-pat-ref-mut-and-ref.rs:131:29 + --> $DIR/borrowck-pat-ref-mut-and-ref.rs:130:29 | LL | let ref a @ (ref mut b, ref mut c) = (U, U); | --------------------^^^^^^^^^- diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs index a208d0087ff..8faaa1c881f 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.rs @@ -1,7 +1,6 @@ // Test that `ref mut x @ ref mut y` and varieties of that are not allowed. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct U; diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index 1cd3e267b99..2e0f5fcabdd 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -1,5 +1,5 @@ error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:28:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:27:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -8,7 +8,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:32:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:31:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -17,7 +17,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:35:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:34:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -26,7 +26,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:38:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:37:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -35,7 +35,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:42:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:41:9 | LL | let ref mut a @ ref mut b = U; | ---------^^^--------- @@ -44,7 +44,7 @@ LL | let ref mut a @ ref mut b = U; | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:46:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:45:9 | LL | let ref mut a @ ( | ^-------- @@ -66,7 +66,7 @@ LL | | ) = (U, [U, U, U]); | |_____^ error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:56:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:55:9 | LL | let ref mut a @ ( | ^-------- @@ -88,7 +88,7 @@ LL | | ) = (u(), [u(), u(), u()]); | |_________^ error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:66:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:65:9 | LL | let a @ (ref mut b, ref mut c) = (U, U); | -^^^^---------^^---------^ @@ -99,7 +99,7 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:69:9 | LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | -^^^^-^^^-^^-^^ @@ -111,7 +111,7 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:73:9 | LL | let a @ &mut ref mut b = &mut U; | -^^^^^^^^--------- @@ -121,7 +121,7 @@ LL | let a @ &mut ref mut b = &mut U; | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait error: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:77:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9 | LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | -^^^^^^^^^---------^^---------^ @@ -132,7 +132,7 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:81:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -141,7 +141,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:82:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:81:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -150,7 +150,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:88:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:87:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -159,7 +159,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:88:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:87:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -168,7 +168,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -177,7 +177,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -186,7 +186,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:9 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^---------^ @@ -195,7 +195,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:37 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:37 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------^^^^^^^---------^ @@ -204,7 +204,7 @@ LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:11:11 + --> $DIR/borrowck-pat-ref-mut-twice.rs:10:11 | LL | fn f1(ref mut a @ ref mut b: U) {} | ---------^^^--------- @@ -213,7 +213,7 @@ LL | fn f1(ref mut a @ ref mut b: U) {} | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:13:11 + --> $DIR/borrowck-pat-ref-mut-twice.rs:12:11 | LL | fn f2(ref mut a @ ref mut b: U) {} | ---------^^^--------- @@ -222,7 +222,7 @@ LL | fn f2(ref mut a @ ref mut b: U) {} | first mutable borrow, by `a`, occurs here error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:16:9 + --> $DIR/borrowck-pat-ref-mut-twice.rs:15:9 | LL | ref mut a @ [ | ^-------- @@ -240,7 +240,7 @@ LL | | ] : [[U; 4]; 5] | |_________^ error: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:24:22 + --> $DIR/borrowck-pat-ref-mut-twice.rs:23:22 | LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | ---------^^^------------- @@ -250,7 +250,7 @@ LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | first mutable borrow, by `a`, occurs here error: cannot move out of value because it is borrowed - --> $DIR/borrowck-pat-ref-mut-twice.rs:24:34 + --> $DIR/borrowck-pat-ref-mut-twice.rs:23:34 | LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | ---------^^^- @@ -259,7 +259,7 @@ LL | fn f4_also_moved(ref mut a @ ref mut b @ c: U) {} | value borrowed, by `b`, here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:28:21 + --> $DIR/borrowck-pat-ref-mut-twice.rs:27:21 | LL | let ref mut a @ ref mut b = U; | ------------^^^^^^^^^ @@ -271,7 +271,7 @@ LL | drop(a); | - first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:38:21 + --> $DIR/borrowck-pat-ref-mut-twice.rs:37:21 | LL | let ref mut a @ ref mut b = U; | ------------^^^^^^^^^ @@ -283,7 +283,7 @@ LL | *a = U; | ------ first borrow later used here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:66:25 + --> $DIR/borrowck-pat-ref-mut-twice.rs:65:25 | LL | let a @ (ref mut b, ref mut c) = (U, U); | ----------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait @@ -292,7 +292,7 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:70:21 + --> $DIR/borrowck-pat-ref-mut-twice.rs:69:21 | LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | ------------^-- -------- move occurs because value has type `&mut (U, [U; 2])`, which does not implement the `Copy` trait @@ -301,7 +301,7 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:74:18 + --> $DIR/borrowck-pat-ref-mut-twice.rs:73:18 | LL | let a @ &mut ref mut b = &mut U; | ---------^^^^^^^^^ ------ move occurs because value has type `&mut U`, which does not implement the `Copy` trait @@ -310,7 +310,7 @@ LL | let a @ &mut ref mut b = &mut U; | value moved here error[E0382]: borrow of moved value - --> $DIR/borrowck-pat-ref-mut-twice.rs:77:30 + --> $DIR/borrowck-pat-ref-mut-twice.rs:76:30 | LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | ---------------------^^^^^^^^^- ----------- move occurs because value has type `&mut (U, U)`, which does not implement the `Copy` trait @@ -319,7 +319,7 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | value moved here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:24 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:24 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------------^^^^^^^^^- @@ -331,7 +331,7 @@ LL | *a = Err(U); | ----------- first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:95:53 + --> $DIR/borrowck-pat-ref-mut-twice.rs:94:53 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ----------------^^^^^^^^^- @@ -343,7 +343,7 @@ LL | *a = Err(U); | ----------- first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:24 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:24 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ---------------^^^^^^^^^- @@ -355,7 +355,7 @@ LL | drop(a); | - first borrow later used here error[E0499]: cannot borrow value as mutable more than once at a time - --> $DIR/borrowck-pat-ref-mut-twice.rs:107:53 + --> $DIR/borrowck-pat-ref-mut-twice.rs:106:53 | LL | ref mut a @ Ok(ref mut b) | ref mut a @ Err(ref mut b) => { | ----------------^^^^^^^^^- diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs index 821d4b42962..3954d17e1c2 100644 --- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.rs @@ -1,7 +1,6 @@ // Test that mixing `Copy` and non-`Copy` types in `@` patterns is forbidden. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] #[derive(Copy, Clone)] struct C; diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr index 7e89008a604..cc2786a13f4 100644 --- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr +++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr @@ -1,5 +1,5 @@ error[E0382]: use of moved value - --> $DIR/copy-and-move-mixed.rs:12:19 + --> $DIR/copy-and-move-mixed.rs:11:19 | LL | let a @ NC(b, c) = NC(C, C); | ----------^- -------- move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait @@ -8,7 +8,7 @@ LL | let a @ NC(b, c) = NC(C, C); | value moved here error[E0382]: use of moved value - --> $DIR/copy-and-move-mixed.rs:15:19 + --> $DIR/copy-and-move-mixed.rs:14:19 | LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | ----------^^^^^^^^^^^^- --------------- move occurs because value has type `NC<C, NC<C, C>>`, which does not implement the `Copy` trait @@ -17,7 +17,7 @@ LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | value moved here error[E0382]: use of moved value - --> $DIR/copy-and-move-mixed.rs:15:29 + --> $DIR/copy-and-move-mixed.rs:14:29 | LL | let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C)); | ----------^- diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs index a45497229ac..276088b9a9e 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.rs @@ -8,7 +8,6 @@ // this would create problems for the generalization aforementioned. #![feature(bindings_after_at)] -#![feature(move_ref_pattern)] fn main() { struct NotCopy; diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index a63a5a1e6c7..11d5e24f34e 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -1,5 +1,5 @@ error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:28:9 + --> $DIR/default-binding-modes-both-sides-independent.rs:27:9 | LL | let ref a @ b = NotCopy; | -----^^^- @@ -8,7 +8,7 @@ LL | let ref a @ b = NotCopy; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:31:9 + --> $DIR/default-binding-modes-both-sides-independent.rs:30:9 | LL | let ref mut a @ b = NotCopy; | ---------^^^- @@ -17,7 +17,7 @@ LL | let ref mut a @ b = NotCopy; | value borrowed, by `a`, here error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:36:12 + --> $DIR/default-binding-modes-both-sides-independent.rs:35:12 | LL | Ok(ref a @ b) | Err(b @ ref a) => { | -----^^^- @@ -26,7 +26,7 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | value borrowed, by `a`, here error: borrow of moved value - --> $DIR/default-binding-modes-both-sides-independent.rs:36:29 + --> $DIR/default-binding-modes-both-sides-independent.rs:35:29 | LL | Ok(ref a @ b) | Err(b @ ref a) => { | -^^^----- @@ -36,7 +36,7 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:44:9 + --> $DIR/default-binding-modes-both-sides-independent.rs:43:9 | LL | ref a @ b => { | -----^^^- @@ -45,7 +45,7 @@ LL | ref a @ b => { | value borrowed, by `a`, here error[E0505]: cannot move out of value because it is borrowed - --> $DIR/default-binding-modes-both-sides-independent.rs:31:21 + --> $DIR/default-binding-modes-both-sides-independent.rs:30:21 | LL | let ref mut a @ b = NotCopy; | ------------^ diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs index d2d4e61e049..5445696fdff 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(move_ref_pattern)] - fn main() {} struct U; diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs index 3ee008fd84f..9c320edc4dc 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() {} struct U; diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index d718ee29cf9..285c203f382 100644 --- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -1,5 +1,5 @@ error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:10:24 + --> $DIR/borrowck-move-ref-pattern.rs:8:24 | LL | let hold_all = &arr; | ---- borrow of `arr` occurs here @@ -10,7 +10,7 @@ LL | drop(hold_all); | -------- borrow later used here error[E0384]: cannot assign twice to immutable variable `_x1` - --> $DIR/borrowck-move-ref-pattern.rs:11:5 + --> $DIR/borrowck-move-ref-pattern.rs:9:5 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | --- @@ -21,7 +21,7 @@ LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:13:10 + --> $DIR/borrowck-move-ref-pattern.rs:11:10 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ------------ borrow of `arr[..]` occurs here @@ -32,7 +32,7 @@ LL | drop(_x0_hold); | -------- borrow later used here error[E0502]: cannot borrow `arr[..]` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-move-ref-pattern.rs:15:16 + --> $DIR/borrowck-move-ref-pattern.rs:13:16 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ---------------- immutable borrow occurs here @@ -44,7 +44,7 @@ LL | drop(xs_hold); | ------- immutable borrow later used here error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:15:29 + --> $DIR/borrowck-move-ref-pattern.rs:13:29 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ---------------- borrow of `arr[..]` occurs here @@ -56,7 +56,7 @@ LL | drop(xs_hold); | ------- borrow later used here error[E0505]: cannot move out of `arr[..]` because it is borrowed - --> $DIR/borrowck-move-ref-pattern.rs:15:34 + --> $DIR/borrowck-move-ref-pattern.rs:13:34 | LL | let [ref _x0_hold, _x1, ref xs_hold @ ..] = arr; | ---------------- borrow of `arr[..]` occurs here @@ -68,7 +68,7 @@ LL | drop(xs_hold); | ------- borrow later used here error[E0384]: cannot assign twice to immutable variable `_x1` - --> $DIR/borrowck-move-ref-pattern.rs:25:5 + --> $DIR/borrowck-move-ref-pattern.rs:23:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | --- @@ -79,7 +79,7 @@ LL | _x1 = U; | ^^^^^^^ cannot assign twice to immutable variable error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-move-ref-pattern.rs:26:20 + --> $DIR/borrowck-move-ref-pattern.rs:24:20 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- immutable borrow occurs here @@ -91,7 +91,7 @@ LL | *_x0 = U; | -------- immutable borrow later used here error[E0502]: cannot borrow `tup.0` as mutable because it is also borrowed as immutable - --> $DIR/borrowck-move-ref-pattern.rs:27:10 + --> $DIR/borrowck-move-ref-pattern.rs:25:10 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- immutable borrow occurs here @@ -102,7 +102,7 @@ LL | *_x0 = U; | -------- immutable borrow later used here error[E0594]: cannot assign to `*_x0` which is behind a `&` reference - --> $DIR/borrowck-move-ref-pattern.rs:28:5 + --> $DIR/borrowck-move-ref-pattern.rs:26:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- help: consider changing this to be a mutable reference: `ref mut _x0` @@ -111,7 +111,7 @@ LL | *_x0 = U; | ^^^^^^^^ `_x0` is a `&` reference, so the data it refers to cannot be written error[E0594]: cannot assign to `*_x2` which is behind a `&` reference - --> $DIR/borrowck-move-ref-pattern.rs:29:5 + --> $DIR/borrowck-move-ref-pattern.rs:27:5 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | ------- help: consider changing this to be a mutable reference: `ref mut _x2` @@ -120,7 +120,7 @@ LL | *_x2 = U; | ^^^^^^^^ `_x2` is a `&` reference, so the data it refers to cannot be written error[E0382]: use of moved value: `tup.1` - --> $DIR/borrowck-move-ref-pattern.rs:30:10 + --> $DIR/borrowck-move-ref-pattern.rs:28:10 | LL | let (ref _x0, _x1, ref _x2, ..) = tup; | --- value moved here @@ -131,7 +131,7 @@ LL | drop(tup.1); = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `tup.1` - --> $DIR/borrowck-move-ref-pattern.rs:31:20 + --> $DIR/borrowck-move-ref-pattern.rs:29:20 | LL | drop(tup.1); | ----- value moved here @@ -141,7 +141,7 @@ LL | let _x1_hold = &tup.1; = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-move-ref-pattern.rs:33:20 + --> $DIR/borrowck-move-ref-pattern.rs:31:20 | LL | let (.., ref mut _x3) = tup; | ----------- mutable borrow occurs here @@ -152,7 +152,7 @@ LL | drop(_x3); | --- mutable borrow later used here error[E0499]: cannot borrow `tup.3` as mutable more than once at a time - --> $DIR/borrowck-move-ref-pattern.rs:34:20 + --> $DIR/borrowck-move-ref-pattern.rs:32:20 | LL | let (.., ref mut _x3) = tup; | ----------- first mutable borrow occurs here @@ -164,7 +164,7 @@ LL | drop(_x3); | --- first borrow later used here error[E0499]: cannot borrow `tup.3` as mutable more than once at a time - --> $DIR/borrowck-move-ref-pattern.rs:35:14 + --> $DIR/borrowck-move-ref-pattern.rs:33:14 | LL | let (.., ref mut _x3) = tup; | ----------- first mutable borrow occurs here @@ -176,7 +176,7 @@ LL | drop(_x3); | --- first borrow later used here error[E0502]: cannot borrow `tup.3` as immutable because it is also borrowed as mutable - --> $DIR/borrowck-move-ref-pattern.rs:36:14 + --> $DIR/borrowck-move-ref-pattern.rs:34:14 | LL | let (.., ref mut _x3) = tup; | ----------- mutable borrow occurs here @@ -187,7 +187,7 @@ LL | drop(_x3); | --- mutable borrow later used here error[E0382]: use of moved value: `tup` - --> $DIR/borrowck-move-ref-pattern.rs:45:14 + --> $DIR/borrowck-move-ref-pattern.rs:43:14 | LL | let mut tup = (U, U, U); | ------- move occurs because `tup` has type `(U, U, U)`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs index 08fb5cd2e16..18663c3fe3f 100644 --- a/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs +++ b/src/test/ui/pattern/move-ref-patterns/by-move-sub-pat-unreachable.rs @@ -4,7 +4,6 @@ // check-pass -#![feature(move_ref_pattern)] #![feature(bindings_after_at)] fn main() { diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs deleted file mode 100644 index fb92eb1ba32..00000000000 --- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.rs +++ /dev/null @@ -1,23 +0,0 @@ -fn main() { - #[derive(Clone)] - struct X { - x: (), - } - let mut tup = (X { x: () }, X { x: () }); - match Some(tup.clone()) { - Some((y, ref z)) => {} - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - None => panic!(), - } - - let (ref a, b) = tup.clone(); - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - - let (a, mut b) = &tup; - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - //~| ERROR cannot move out of a shared reference - - let (mut a, b) = &mut tup; - //~^ ERROR binding by-move and by-ref in the same pattern is unstable - //~| ERROR cannot move out of a mutable reference -} diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr deleted file mode 100644 index 5335569a972..00000000000 --- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr +++ /dev/null @@ -1,66 +0,0 @@ -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:8:15 - | -LL | Some((y, ref z)) => {} - | ^ ----- by-ref pattern here - | | - | by-move pattern here - | - = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:13:17 - | -LL | let (ref a, b) = tup.clone(); - | ----- ^ by-move pattern here - | | - | by-ref pattern here - | - = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:16:13 - | -LL | let (a, mut b) = &tup; - | - ^^^^^ by-move pattern here - | | - | by-ref pattern here - | - = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0658]: binding by-move and by-ref in the same pattern is unstable - --> $DIR/feature-gate-move_ref_pattern.rs:20:10 - | -LL | let (mut a, b) = &mut tup; - | ^^^^^ - by-ref pattern here - | | - | by-move pattern here - | - = note: see issue #68354 <https://github.com/rust-lang/rust/issues/68354> for more information - = help: add `#![feature(move_ref_pattern)]` to the crate attributes to enable - -error[E0507]: cannot move out of a shared reference - --> $DIR/feature-gate-move_ref_pattern.rs:16:22 - | -LL | let (a, mut b) = &tup; - | ----- ^^^^ - | | - | data moved here - | move occurs because `b` has type `X`, which does not implement the `Copy` trait - -error[E0507]: cannot move out of a mutable reference - --> $DIR/feature-gate-move_ref_pattern.rs:20:22 - | -LL | let (mut a, b) = &mut tup; - | ----- ^^^^^^^^ - | | - | data moved here - | move occurs because `a` has type `X`, which does not implement the `Copy` trait - -error: aborting due to 6 previous errors - -Some errors have detailed explanations: E0507, E0658. -For more information about an error, try `rustc --explain E0507`. diff --git a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs index ab7d10d9f83..80effc497ed 100644 --- a/src/test/ui/pattern/move-ref-patterns/issue-53840.rs +++ b/src/test/ui/pattern/move-ref-patterns/issue-53840.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(move_ref_pattern)] - enum E { Foo(String, String, String), } diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs index 4c3ca62e165..ebb1683af7d 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() { struct S; // Not `Copy`. diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr index 9ad84879595..f19fed08917 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr @@ -1,5 +1,5 @@ error[E0382]: borrow of moved value: `tup0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:31:10 | LL | let mut tup0 = (S, S); | -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait @@ -14,7 +14,7 @@ LL | drop(&tup0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:32:10 | LL | let mut tup1 = (S, S, S); | -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ LL | drop(&tup1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:35:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 | LL | let tup2 = (S, S); | ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait @@ -44,7 +44,7 @@ LL | drop(&tup2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:36:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 | LL | let tup3 = (S, S, S); | ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait @@ -59,7 +59,7 @@ LL | drop(&tup3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup4` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:39:10 | LL | let tup4 = (S, S); | ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait @@ -74,7 +74,7 @@ LL | drop(&tup4.0); | ^^^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 | LL | let mut arr0 = [S, S, S]; | -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait @@ -89,7 +89,7 @@ LL | drop(&arr0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:42:36 | LL | let mut arr1 = [S, S, S, S, S]; | -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait @@ -104,7 +104,7 @@ LL | let [_, mov1, mov2, mov3, _] = &arr1; | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:45:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 | LL | let arr2 = [S, S, S]; | ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait @@ -119,7 +119,7 @@ LL | drop(&arr2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:46:36 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 | LL | let arr3 = [S, S, S, S, S]; | ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait @@ -134,7 +134,7 @@ LL | let [_, mov1, mov2, mov3, _] = &arr3; | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:75:10 | LL | let mut tup0: Option<(S, S)> = None; | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -148,7 +148,7 @@ LL | drop(&tup0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:76:10 | LL | let mut tup1: Option<(S, S, S)> = None; | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -163,7 +163,7 @@ LL | drop(&tup1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 | LL | let tup2: Option<(S, S)> = None; | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -178,7 +178,7 @@ LL | drop(&tup2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 | LL | let tup3: Option<(S, S, S)> = None; | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -193,7 +193,7 @@ LL | drop(&tup3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup4` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:21 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:21 | LL | let tup4: Option<(S, S)> = None; | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -208,7 +208,7 @@ LL | m!((ref x, _) = &tup4); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 | LL | let mut arr0: Option<[S; 3]> = None; | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -223,7 +223,7 @@ LL | drop(&arr0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:35 | LL | let mut arr1: Option<[S; 5]> = None; | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait @@ -238,7 +238,7 @@ LL | m!([_, mov1, mov2, mov3, _] = &arr1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:84:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 | LL | let arr2: Option<[S; 3]> = None; | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -253,7 +253,7 @@ LL | drop(&arr2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:85:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 | LL | let arr3: Option<[S; 5]> = None; | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait @@ -267,7 +267,7 @@ LL | m!([_, mov1, mov2, mov3, _] = &arr3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:111:10 | LL | let mut tup0: Option<(S, S)> = None; | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -281,7 +281,7 @@ LL | drop(&tup0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:112:10 | LL | let mut tup1: Option<(S, S, S)> = None; | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -296,7 +296,7 @@ LL | drop(&tup1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 | LL | let tup2: Option<(S, S)> = None; | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -311,7 +311,7 @@ LL | drop(&tup2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 | LL | let tup3: Option<(S, S, S)> = None; | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait @@ -326,7 +326,7 @@ LL | drop(&tup3); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `tup4` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:21 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:21 | LL | let tup4: Option<(S, S)> = None; | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait @@ -341,7 +341,7 @@ LL | m!((ref x, _) = &tup4); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr0` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 | LL | let mut arr0: Option<[S; 3]> = None; | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -356,7 +356,7 @@ LL | drop(&arr0); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr1` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:35 | LL | let mut arr1: Option<[S; 5]> = None; | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait @@ -371,7 +371,7 @@ LL | m!([_, mov1, mov2, mov3, _] = &arr1); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr2` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:120:10 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 | LL | let arr2: Option<[S; 3]> = None; | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait @@ -386,7 +386,7 @@ LL | drop(&arr2); | ^^^^^ value borrowed here after move error[E0382]: borrow of moved value: `arr3` - --> $DIR/move-ref-patterns-closure-captures-inside.rs:121:35 + --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 | LL | let arr3: Option<[S; 5]> = None; | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs index e1844d36e4a..583f70f41aa 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(move_ref_pattern)] - fn main() { struct U; fn accept_fn_once(_: impl FnOnce()) {} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs index 7f1c02c05cb..cd619cc41eb 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() { struct U; fn accept_fn_once(_: &impl FnOnce()) {} diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr index ca82353c1c9..d96e863939c 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures.stderr @@ -1,5 +1,5 @@ error[E0525]: expected a closure that implements the `FnMut` trait, but this closure only implements `FnOnce` - --> $DIR/move-ref-patterns-closure-captures.rs:11:14 + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 | LL | let c1 = || { | ^^ this closure implements `FnOnce`, not `FnMut` @@ -11,7 +11,7 @@ LL | accept_fn_mut(&c1); | ------------- the requirement to implement `FnMut` derives from here error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnOnce` - --> $DIR/move-ref-patterns-closure-captures.rs:11:14 + --> $DIR/move-ref-patterns-closure-captures.rs:9:14 | LL | let c1 = || { | ^^ this closure implements `FnOnce`, not `Fn` @@ -23,7 +23,7 @@ LL | accept_fn(&c1); | --------- the requirement to implement `Fn` derives from here error[E0525]: expected a closure that implements the `Fn` trait, but this closure only implements `FnMut` - --> $DIR/move-ref-patterns-closure-captures.rs:22:14 + --> $DIR/move-ref-patterns-closure-captures.rs:20:14 | LL | let c2 = || { | ^^ this closure implements `FnMut`, not `Fn` diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs index 5c51c47d979..1dd66aad57a 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - fn main() { struct U; diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr index f92699f5c3c..6952c743a30 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/move-ref-patterns-default-binding-modes.rs:10:22 + --> $DIR/move-ref-patterns-default-binding-modes.rs:8:22 | LL | let (a, mut b) = &p; | ----- ^^ @@ -8,7 +8,7 @@ LL | let (a, mut b) = &p; | move occurs because `b` has type `U`, which does not implement the `Copy` trait error[E0507]: cannot move out of a mutable reference - --> $DIR/move-ref-patterns-default-binding-modes.rs:14:22 + --> $DIR/move-ref-patterns-default-binding-modes.rs:12:22 | LL | let (a, mut b) = &mut p; | ----- ^^^^^^ diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs index c78695390b5..1d6d9acead1 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-dynamic-semantics.rs @@ -3,8 +3,6 @@ // This test checks the dynamic semantics and drop order of pattern matching // where a product pattern has both a by-move and by-ref binding. -#![feature(move_ref_pattern)] - use std::cell::RefCell; use std::rc::Rc; diff --git a/src/test/ui/polymorphization/const_parameters/closures.stderr b/src/test/ui/polymorphization/const_parameters/closures.stderr index 266b6e62afd..63335586b76 100644 --- a/src/test/ui/polymorphization/const_parameters/closures.stderr +++ b/src/test/ui/polymorphization/const_parameters/closures.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics, rustc_attrs)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: item has unused generic parameters --> $DIR/closures.rs:19:19 diff --git a/src/test/ui/polymorphization/const_parameters/functions.stderr b/src/test/ui/polymorphization/const_parameters/functions.stderr index e379e32c1fc..c976a5b62aa 100644 --- a/src/test/ui/polymorphization/const_parameters/functions.stderr +++ b/src/test/ui/polymorphization/const_parameters/functions.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics, rustc_attrs)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: item has unused generic parameters --> $DIR/functions.rs:15:8 diff --git a/src/test/ui/polymorphization/generators.stderr b/src/test/ui/polymorphization/generators.stderr index c59055ba9d6..b2b32db045d 100644 --- a/src/test/ui/polymorphization/generators.stderr +++ b/src/test/ui/polymorphization/generators.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics, generators, generator_trait, rustc_attrs)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: item has unused generic parameters --> $DIR/generators.rs:36:5 diff --git a/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs new file mode 100644 index 00000000000..2d4f6010012 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/actix-web-2.0.0/src/extract.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! tuple_from_req { + ($T:ident) => { + #[my_macro] struct Three($T); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs new file mode 100644 index 00000000000..2d4f6010012 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/actix-web/src/extract.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! tuple_from_req { + ($T:ident) => { + #[my_macro] struct Three($T); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs new file mode 100644 index 00000000000..9ec6aba63f3 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/actori-web-2.0.0/src/extract.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! tuple_from_req { + ($T:ident) => { + #[my_macro] struct Four($T); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs b/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs new file mode 100644 index 00000000000..9ec6aba63f3 --- /dev/null +++ b/src/test/ui/proc-macro/group-compat-hack/actori-web/src/extract.rs @@ -0,0 +1,7 @@ +// ignore-test this is not a test + +macro_rules! tuple_from_req { + ($T:ident) => { + #[my_macro] struct Four($T); + } +} diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs index bc82a2ff196..652fabf34ac 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.rs @@ -45,5 +45,33 @@ mod with_version { other!(Foo); } +mod actix_web_test { + include!("actix-web/src/extract.rs"); + + struct Foo; + tuple_from_req!(Foo); +} + +mod actix_web_version_test { + include!("actix-web-2.0.0/src/extract.rs"); + + struct Foo; + tuple_from_req!(Foo); +} + +mod actori_web_test { + include!("actori-web/src/extract.rs"); + + struct Foo; + tuple_from_req!(Foo); +} + +mod actori_web_version_test { + include!("actori-web-2.0.0/src/extract.rs"); + + struct Foo; + tuple_from_req!(Foo); +} + fn main() {} diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout index e83bc9f8fca..c6b18ab674b 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout @@ -4,3 +4,7 @@ Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/gro Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }] Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }] Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web/src/extract.rs:5:21: 5:27 (#33) }, Ident { ident: "Three", span: $DIR/actix-web/src/extract.rs:5:28: 5:33 (#33) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:52:21: 52:24 (#0) }], span: $DIR/actix-web/src/extract.rs:5:33: 5:37 (#33) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web/src/extract.rs:5:37: 5:38 (#33) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actix-web-2.0.0/src/extract.rs:5:21: 5:27 (#38) }, Ident { ident: "Three", span: $DIR/actix-web-2.0.0/src/extract.rs:5:28: 5:33 (#38) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:59:21: 59:24 (#0) }], span: $DIR/actix-web-2.0.0/src/extract.rs:5:33: 5:37 (#38) }, Punct { ch: ';', spacing: Alone, span: $DIR/actix-web-2.0.0/src/extract.rs:5:37: 5:38 (#38) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web/src/extract.rs:5:21: 5:27 (#43) }, Ident { ident: "Four", span: $DIR/actori-web/src/extract.rs:5:28: 5:32 (#43) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:66:21: 66:24 (#0) }], span: $DIR/actori-web/src/extract.rs:5:32: 5:36 (#43) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web/src/extract.rs:5:36: 5:37 (#43) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/actori-web-2.0.0/src/extract.rs:5:21: 5:27 (#48) }, Ident { ident: "Four", span: $DIR/actori-web-2.0.0/src/extract.rs:5:28: 5:32 (#48) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:73:21: 73:24 (#0) }], span: $DIR/actori-web-2.0.0/src/extract.rs:5:32: 5:36 (#48) }, Punct { ch: ';', spacing: Alone, span: $DIR/actori-web-2.0.0/src/extract.rs:5:36: 5:37 (#48) }] diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.rs b/src/test/ui/proc-macro/invalid-punct-ident-1.rs index 3f78dea917b..a3133a1a790 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.rs @@ -9,6 +9,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr index fc821d29d5a..5ef22709cb3 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-1.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-1.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-1.rs:16:1 + --> $DIR/invalid-punct-ident-1.rs:19:1 | LL | invalid_punct!(); | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.rs b/src/test/ui/proc-macro/invalid-punct-ident-2.rs index 4e89e80ae7c..04a0a873311 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.rs @@ -9,6 +9,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr index 8b30edaf85c..4bd7a5351d3 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-2.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-2.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-2.rs:16:1 + --> $DIR/invalid-punct-ident-2.rs:19:1 | LL | invalid_ident!(); | ^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.rs b/src/test/ui/proc-macro/invalid-punct-ident-3.rs index 8d8ce8f932e..aebba341625 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.rs +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.rs @@ -9,6 +9,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate invalid_punct_ident; diff --git a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr index d46fab08e14..072d13956ac 100644 --- a/src/test/ui/proc-macro/invalid-punct-ident-3.stderr +++ b/src/test/ui/proc-macro/invalid-punct-ident-3.stderr @@ -1,5 +1,5 @@ error: proc macro panicked - --> $DIR/invalid-punct-ident-3.rs:16:1 + --> $DIR/invalid-punct-ident-3.rs:19:1 | LL | invalid_raw_ident!(); | ^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.rs b/src/test/ui/proc-macro/issue-75734-pp-paren.rs new file mode 100644 index 00000000000..faa93787d13 --- /dev/null +++ b/src/test/ui/proc-macro/issue-75734-pp-paren.rs @@ -0,0 +1,26 @@ +// Regression test for issue #75734 +// Ensures that we don't lose tokens when pretty-printing would +// normally insert extra parentheses. + +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +#[macro_use] +extern crate test_macros; + +macro_rules! mul_2 { + ($val:expr) => { + print_bang!($val * 2); + }; +} + + +#[print_attr] +fn main() { + &|_: u8| {}; + mul_2!(1 + 1); +} diff --git a/src/test/ui/proc-macro/issue-75734-pp-paren.stdout b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout new file mode 100644 index 00000000000..b33b85f1705 --- /dev/null +++ b/src/test/ui/proc-macro/issue-75734-pp-paren.stdout @@ -0,0 +1,134 @@ +PRINT-ATTR INPUT (DISPLAY): fn main() { & | _ : u8 | { } ; mul_2 ! (1 + 1) ; } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/issue-75734-pp-paren.rs:23:1: 23:3 (#0), + }, + Ident { + ident: "main", + span: $DIR/issue-75734-pp-paren.rs:23:4: 23:8 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75734-pp-paren.rs:23:8: 23:10 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '&', + spacing: Joint, + span: $DIR/issue-75734-pp-paren.rs:24:5: 24:6 (#0), + }, + Punct { + ch: '|', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:24:6: 24:7 (#0), + }, + Ident { + ident: "_", + span: $DIR/issue-75734-pp-paren.rs:24:7: 24:8 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:24:8: 24:9 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75734-pp-paren.rs:24:10: 24:12 (#0), + }, + Punct { + ch: '|', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:24:12: 24:13 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75734-pp-paren.rs:24:14: 24:16 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:24:16: 24:17 (#0), + }, + Ident { + ident: "mul_2", + span: $DIR/issue-75734-pp-paren.rs:25:5: 25:10 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:25:10: 25:11 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:25:12: 25:13 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:25:14: 25:15 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:25:16: 25:17 (#0), + }, + ], + span: $DIR/issue-75734-pp-paren.rs:25:11: 25:18 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:25:18: 25:19 (#0), + }, + ], + span: $DIR/issue-75734-pp-paren.rs:23:11: 26:2 (#0), + }, +] +PRINT-BANG INPUT (DISPLAY): 1 + 1 * 2 +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:25:12: 25:13 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:25:14: 25:15 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:25:16: 25:17 (#0), + }, + ], + span: $DIR/issue-75734-pp-paren.rs:17:21: 17:25 (#7), + }, + Punct { + ch: '*', + spacing: Alone, + span: $DIR/issue-75734-pp-paren.rs:17:26: 17:27 (#7), + }, + Literal { + kind: Integer, + symbol: "2", + suffix: None, + span: $DIR/issue-75734-pp-paren.rs:17:28: 17:29 (#7), + }, +] diff --git a/src/test/ui/proc-macro/load-panic-backtrace.rs b/src/test/ui/proc-macro/load-panic-backtrace.rs index 90fe109abb8..4a3ba9aee74 100644 --- a/src/test/ui/proc-macro/load-panic-backtrace.rs +++ b/src/test/ui/proc-macro/load-panic-backtrace.rs @@ -10,6 +10,9 @@ // normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" // normalize-stderr-test "note: compiler flags.*\n\n" -> "" // normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" +// normalize-stderr-test "query stack during panic:\n" -> "" +// normalize-stderr-test "we're just showing a limited slice of the query stack\n" -> "" +// normalize-stderr-test "end of query stack\n" -> "" #[macro_use] extern crate test_macros; diff --git a/src/test/ui/proc-macro/load-panic-backtrace.stderr b/src/test/ui/proc-macro/load-panic-backtrace.stderr index 63378b5735a..f825047e331 100644 --- a/src/test/ui/proc-macro/load-panic-backtrace.stderr +++ b/src/test/ui/proc-macro/load-panic-backtrace.stderr @@ -1,6 +1,6 @@ at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5 error: proc-macro derive panicked - --> $DIR/load-panic-backtrace.rs:17:10 + --> $DIR/load-panic-backtrace.rs:20:10 | LL | #[derive(Panic)] | ^^^^^ diff --git a/src/test/ui/reject-specialized-drops-8142.stderr b/src/test/ui/reject-specialized-drops-8142.stderr index f819faa2789..eac24617533 100644 --- a/src/test/ui/reject-specialized-drops-8142.stderr +++ b/src/test/ui/reject-specialized-drops-8142.stderr @@ -1,15 +1,3 @@ -error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not - --> $DIR/reject-specialized-drops-8142.rs:67:21 - | -LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT - | ^^^^^ - | -note: the implementor must specify the same requirement - --> $DIR/reject-specialized-drops-8142.rs:21:1 - | -LL | union Union<T: Copy> { f: T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0367]: `Drop` impl requires `'adds_bnd: 'al` but the struct it is implemented for does not --> $DIR/reject-specialized-drops-8142.rs:23:20 | @@ -145,6 +133,18 @@ note: the implementor must specify the same requirement LL | struct TupleStruct<T>(T); | ^^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0367]: `Drop` impl requires `AddsBnd: Bound` but the union it is implemented for does not + --> $DIR/reject-specialized-drops-8142.rs:67:21 + | +LL | impl<AddsBnd:Copy + Bound> Drop for Union<AddsBnd> { fn drop(&mut self) { } } // REJECT + | ^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/reject-specialized-drops-8142.rs:21:1 + | +LL | union Union<T: Copy> { f: T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + error: aborting due to 11 previous errors Some errors have detailed explanations: E0308, E0366, E0367, E0495. diff --git a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr index 7f8151db06f..5de8eb21582 100644 --- a/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr +++ b/src/test/ui/resolve/issue-65035-static-with-parent-generics.stderr @@ -48,6 +48,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete error: aborting due to 5 previous errors; 1 warning emitted diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index 77429f800f1..807dadf417b 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -2,17 +2,57 @@ error[E0423]: expected value, found enum `n::Z` --> $DIR/privacy-enum-ctor.rs:23:9 | LL | n::Z; - | ^^^^ help: try using one of the enum's variants: `m::Z::Unit` + | ^^^^ | - = help: you might have meant to use one of the enum's other variants that have fields +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 + | +LL | / pub(in m) enum Z { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_________^ +help: you might have meant to use the following enum variant + | +LL | m::Z::Unit; + | ^^^^^^^^^^ +help: the following enum variants are available + | +LL | (m::Z::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (m::Z::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found enum `Z` --> $DIR/privacy-enum-ctor.rs:25:9 | LL | Z; - | ^ help: try using one of the enum's variants: `m::Z::Unit` + | ^ + | +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 | - = help: you might have meant to use one of the enum's other variants that have fields +LL | / pub(in m) enum Z { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_________^ +help: you might have meant to use the following enum variant + | +LL | m::Z::Unit; + | ^^^^^^^^^^ +help: the following enum variants are available + | +LL | (m::Z::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | (m::Z::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0423]: expected value, found struct variant `Z::Struct` --> $DIR/privacy-enum-ctor.rs:29:20 @@ -34,11 +74,27 @@ LL | fn f() { LL | let _: E = m::E; | ^^^^ | - = help: you might have meant to use one of the enum's other variants that have fields -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:2:5 + | +LL | / pub enum E { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_____^ +help: you might have meant to use the following enum variant | LL | let _: E = E::Unit; | ^^^^^^^ +help: the following enum variants are available + | +LL | let _: E = (E::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^ +LL | let _: E = (E::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: a function with a similar name exists | LL | let _: E = m::f; @@ -67,11 +123,27 @@ error[E0423]: expected value, found enum `E` LL | let _: E = E; | ^ | - = help: you might have meant to use one of the enum's other variants that have fields -help: try using one of the enum's variants +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:2:5 + | +LL | / pub enum E { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_____^ +help: you might have meant to use the following enum variant | LL | let _: E = E::Unit; | ^^^^^^^ +help: the following enum variants are available + | +LL | let _: E = (E::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^ +LL | let _: E = (E::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider importing one of these items instead | LL | use std::f32::consts::E; @@ -112,9 +184,29 @@ error[E0423]: expected value, found enum `m::n::Z` --> $DIR/privacy-enum-ctor.rs:57:16 | LL | let _: Z = m::n::Z; - | ^^^^^^^ help: try using one of the enum's variants: `m::Z::Unit` + | ^^^^^^^ + | +note: the enum is defined here + --> $DIR/privacy-enum-ctor.rs:11:9 + | +LL | / pub(in m) enum Z { +LL | | Fn(u8), +LL | | Struct { +LL | | s: u8, +LL | | }, +LL | | Unit, +LL | | } + | |_________^ +help: you might have meant to use the following enum variant + | +LL | let _: Z = m::Z::Unit; + | ^^^^^^^^^^ +help: the following enum variants are available | - = help: you might have meant to use one of the enum's other variants that have fields +LL | let _: Z = (m::Z::Fn(/* fields */)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _: Z = (m::Z::Struct { /* fields */ }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0412]: cannot find type `Z` in this scope --> $DIR/privacy-enum-ctor.rs:61:12 diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.rs b/src/test/ui/rfc-2005-default-binding-mode/for.rs index aa42c7bb9c2..d6c5a13b1bd 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/for.rs +++ b/src/test/ui/rfc-2005-default-binding-mode/for.rs @@ -1,5 +1,3 @@ -#![feature(move_ref_pattern)] - struct Foo {} pub fn main() { diff --git a/src/test/ui/rfc-2005-default-binding-mode/for.stderr b/src/test/ui/rfc-2005-default-binding-mode/for.stderr index ef624313880..9cc20a7bf31 100644 --- a/src/test/ui/rfc-2005-default-binding-mode/for.stderr +++ b/src/test/ui/rfc-2005-default-binding-mode/for.stderr @@ -1,5 +1,5 @@ error[E0507]: cannot move out of a shared reference - --> $DIR/for.rs:8:23 + --> $DIR/for.rs:6:23 | LL | for (n, mut m) in &tups { | ----- ^^^^^ diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index d38a3aba46f..bd39650702c 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -507,6 +507,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: the feature `let_chains` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/disallowed-positions.rs:22:12 diff --git a/src/test/ui/self/self-in-typedefs.rs b/src/test/ui/self/self-in-typedefs.rs index 3b1eb9e1dfa..81e557d53a6 100644 --- a/src/test/ui/self/self-in-typedefs.rs +++ b/src/test/ui/self/self-in-typedefs.rs @@ -1,7 +1,4 @@ // build-pass (FIXME(62277): could be check-pass?) - -#![feature(untagged_unions)] - #![allow(dead_code)] use std::mem::ManuallyDrop; diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr index 40c3219bf27..5cda17fd6a1 100644 --- a/src/test/ui/span/issue-34264.stderr +++ b/src/test/ui/span/issue-34264.stderr @@ -53,13 +53,16 @@ LL | fn bar(_: x, y: usize) {} error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:7:5 | -LL | fn foo(Option<i32>, String) {} - | --------------------------- defined here -... LL | foo(Some(42), 2, ""); | ^^^ -------- - -- supplied 3 arguments | | | expected 2 arguments + | +note: function defined here + --> $DIR/issue-34264.rs:1:4 + | +LL | fn foo(Option<i32>, String) {} + | ^^^ ----------- ------ error[E0308]: mismatched types --> $DIR/issue-34264.rs:8:13 @@ -70,13 +73,16 @@ LL | bar("", ""); error[E0061]: this function takes 2 arguments but 3 arguments were supplied --> $DIR/issue-34264.rs:10:5 | -LL | fn bar(x, y: usize) {} - | ------------------- defined here -... LL | bar(1, 2, 3); | ^^^ - - - supplied 3 arguments | | | expected 2 arguments + | +note: function defined here + --> $DIR/issue-34264.rs:3:4 + | +LL | fn bar(x, y: usize) {} + | ^^^ - -------- error: aborting due to 6 previous errors diff --git a/src/test/ui/span/missing-unit-argument.stderr b/src/test/ui/span/missing-unit-argument.stderr index f6344fba3d3..b15da2cb479 100644 --- a/src/test/ui/span/missing-unit-argument.stderr +++ b/src/test/ui/span/missing-unit-argument.stderr @@ -12,34 +12,42 @@ LL | let _: Result<(), String> = Ok(()); error[E0061]: this function takes 2 arguments but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:12:5 | -LL | fn foo(():(), ():()) {} - | -------------------- defined here -... LL | foo(); | ^^^-- supplied 0 arguments | | | expected 2 arguments + | +note: function defined here + --> $DIR/missing-unit-argument.rs:1:4 + | +LL | fn foo(():(), ():()) {} + | ^^^ ----- ----- error[E0061]: this function takes 2 arguments but 1 argument was supplied --> $DIR/missing-unit-argument.rs:13:5 | -LL | fn foo(():(), ():()) {} - | -------------------- defined here -... LL | foo(()); | ^^^ -- supplied 1 argument | | | expected 2 arguments + | +note: function defined here + --> $DIR/missing-unit-argument.rs:1:4 + | +LL | fn foo(():(), ():()) {} + | ^^^ ----- ----- error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:14:5 | -LL | fn bar(():()) {} - | ------------- defined here -... LL | bar(); | ^^^-- supplied 0 arguments | +note: function defined here + --> $DIR/missing-unit-argument.rs:2:4 + | +LL | fn bar(():()) {} + | ^^^ ----- help: expected the unit value `()`; create it with empty parentheses | LL | bar(()); @@ -48,12 +56,14 @@ LL | bar(()); error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:15:7 | -LL | fn baz(self, (): ()) { } - | -------------------- defined here -... LL | S.baz(); | ^^^- supplied 0 arguments | +note: associated function defined here + --> $DIR/missing-unit-argument.rs:6:8 + | +LL | fn baz(self, (): ()) { } + | ^^^ ---- ------ help: expected the unit value `()`; create it with empty parentheses | LL | S.baz(()); @@ -62,12 +72,14 @@ LL | S.baz(()); error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/missing-unit-argument.rs:16:7 | -LL | fn generic<T>(self, _: T) { } - | ------------------------- defined here -... LL | S.generic::<()>(); | ^^^^^^^------ supplied 0 arguments | +note: associated function defined here + --> $DIR/missing-unit-argument.rs:7:8 + | +LL | fn generic<T>(self, _: T) { } + | ^^^^^^^ ---- ---- help: expected the unit value `()`; create it with empty parentheses | LL | S.generic::<()>(()); diff --git a/src/test/ui/specialization/assoc-ty-graph-cycle.stderr b/src/test/ui/specialization/assoc-ty-graph-cycle.stderr index 250f48f8e59..17da34caa70 100644 --- a/src/test/ui/specialization/assoc-ty-graph-cycle.stderr +++ b/src/test/ui/specialization/assoc-ty-graph-cycle.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/cross-crate-defaults.stderr b/src/test/ui/specialization/cross-crate-defaults.stderr index f18bc99d739..e368c2e73b6 100644 --- a/src/test/ui/specialization/cross-crate-defaults.stderr +++ b/src/test/ui/specialization/cross-crate-defaults.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr index 337972ea2b7..4ca3d831198 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/deafult-associated-type-bound-1.rs:19:5 diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr index 8c9da81d277..2bc14dbe3b2 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: can't compare `&'static B` with `B` --> $DIR/deafult-associated-type-bound-2.rs:16:5 diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr index f145b90f216..b5a1877ea19 100644 --- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: the feature `generic_associated_types` is incomplete and may not be safe to use and/or cause compiler crashes --> $DIR/deafult-generic-associated-type-bound.rs:4:12 diff --git a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr index 1b50329719d..d8b9c48c72e 100644 --- a/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr +++ b/src/test/ui/specialization/defaultimpl/allowed-cross-crate.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/out-of-order.stderr b/src/test/ui/specialization/defaultimpl/out-of-order.stderr index deae021a891..9ca915686e8 100644 --- a/src/test/ui/specialization/defaultimpl/out-of-order.stderr +++ b/src/test/ui/specialization/defaultimpl/out-of-order.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/overlap-projection.stderr b/src/test/ui/specialization/defaultimpl/overlap-projection.stderr index 46899ca9954..31d0e6e3882 100644 --- a/src/test/ui/specialization/defaultimpl/overlap-projection.stderr +++ b/src/test/ui/specialization/defaultimpl/overlap-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/projection.stderr b/src/test/ui/specialization/defaultimpl/projection.stderr index 8629c6c52d4..2d5c80d05f0 100644 --- a/src/test/ui/specialization/defaultimpl/projection.stderr +++ b/src/test/ui/specialization/defaultimpl/projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr index 7958eddbeba..3f1a5495e21 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-no-default.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr index dc377dd10c8..163c93550fb 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented-rpass.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr index 9d1eca1d6af..250f0017bea 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-item-not-implemented.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0046]: not all trait items implemented, missing: `foo_two` --> $DIR/specialization-trait-item-not-implemented.rs:18:1 diff --git a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr index 6b8e559bc36..fb623c97f42 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-trait-not-implemented.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0599]: no method named `foo_one` found for struct `MyStruct` in the current scope --> $DIR/specialization-trait-not-implemented.rs:22:29 diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr index dcac310ed06..57b90c457cb 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: the trait bound `U: Eq` is not satisfied --> $DIR/specialization-wfcheck.rs:7:17 diff --git a/src/test/ui/specialization/defaultimpl/validation.stderr b/src/test/ui/specialization/defaultimpl/validation.stderr index 2449849725f..cbf0cef5e74 100644 --- a/src/test/ui/specialization/defaultimpl/validation.stderr +++ b/src/test/ui/specialization/defaultimpl/validation.stderr @@ -16,6 +16,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error: impls of auto traits cannot be default --> $DIR/validation.rs:9:21 diff --git a/src/test/ui/specialization/issue-36804.stderr b/src/test/ui/specialization/issue-36804.stderr index 744d8820424..783a38e6bdc 100644 --- a/src/test/ui/specialization/issue-36804.stderr +++ b/src/test/ui/specialization/issue-36804.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/issue-38091-2.stderr b/src/test/ui/specialization/issue-38091-2.stderr index a314c26ad14..bd5ed498d92 100644 --- a/src/test/ui/specialization/issue-38091-2.stderr +++ b/src/test/ui/specialization/issue-38091-2.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0275]: overflow evaluating the requirement `i32: Check` | diff --git a/src/test/ui/specialization/issue-38091.stderr b/src/test/ui/specialization/issue-38091.stderr index 6be0f26849f..97e5775ab54 100644 --- a/src/test/ui/specialization/issue-38091.stderr +++ b/src/test/ui/specialization/issue-38091.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0277]: the trait bound `(): Valid` is not satisfied --> $DIR/issue-38091.rs:12:5 diff --git a/src/test/ui/specialization/issue-39448.stderr b/src/test/ui/specialization/issue-39448.stderr index f3bb69b8f71..98e49b1bab3 100644 --- a/src/test/ui/specialization/issue-39448.stderr +++ b/src/test/ui/specialization/issue-39448.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0275]: overflow evaluating the requirement `T: FromA<U>` --> $DIR/issue-39448.rs:45:13 diff --git a/src/test/ui/specialization/issue-39618.stderr b/src/test/ui/specialization/issue-39618.stderr index d40d17d8f71..77a45806edb 100644 --- a/src/test/ui/specialization/issue-39618.stderr +++ b/src/test/ui/specialization/issue-39618.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/issue-50452.stderr b/src/test/ui/specialization/issue-50452.stderr index c01817e0b27..2f05c41346f 100644 --- a/src/test/ui/specialization/issue-50452.stderr +++ b/src/test/ui/specialization/issue-50452.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/issue-52050.stderr b/src/test/ui/specialization/issue-52050.stderr index a7564ced055..27070f8e4a1 100644 --- a/src/test/ui/specialization/issue-52050.stderr +++ b/src/test/ui/specialization/issue-52050.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0119]: conflicting implementations of trait `IntoPyDictPointer` for type `()`: --> $DIR/issue-52050.rs:28:1 diff --git a/src/test/ui/specialization/issue-63716-parse-async.stderr b/src/test/ui/specialization/issue-63716-parse-async.stderr index 43620e1ba51..cde17872d6b 100644 --- a/src/test/ui/specialization/issue-63716-parse-async.stderr +++ b/src/test/ui/specialization/issue-63716-parse-async.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/issue-70442.stderr b/src/test/ui/specialization/issue-70442.stderr index f71e4c7dd1c..5ee82e9915b 100644 --- a/src/test/ui/specialization/issue-70442.stderr +++ b/src/test/ui/specialization/issue-70442.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/non-defaulted-item-fail.stderr b/src/test/ui/specialization/non-defaulted-item-fail.stderr index eae045b92c0..85ccbd809b0 100644 --- a/src/test/ui/specialization/non-defaulted-item-fail.stderr +++ b/src/test/ui/specialization/non-defaulted-item-fail.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization, associated_type_defaults)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0520]: `Ty` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/non-defaulted-item-fail.rs:30:5 diff --git a/src/test/ui/specialization/specialization-allowed-cross-crate.stderr b/src/test/ui/specialization/specialization-allowed-cross-crate.stderr index 7d087545725..9605bd08935 100644 --- a/src/test/ui/specialization/specialization-allowed-cross-crate.stderr +++ b/src/test/ui/specialization/specialization-allowed-cross-crate.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-assoc-fns.stderr b/src/test/ui/specialization/specialization-assoc-fns.stderr index b12738604ea..a7c0661a825 100644 --- a/src/test/ui/specialization/specialization-assoc-fns.stderr +++ b/src/test/ui/specialization/specialization-assoc-fns.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-basics.stderr b/src/test/ui/specialization/specialization-basics.stderr index ad00cd81df1..afb2af3803f 100644 --- a/src/test/ui/specialization/specialization-basics.stderr +++ b/src/test/ui/specialization/specialization-basics.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-cross-crate.stderr b/src/test/ui/specialization/specialization-cross-crate.stderr index 7481eed796d..c69130c0aef 100644 --- a/src/test/ui/specialization/specialization-cross-crate.stderr +++ b/src/test/ui/specialization/specialization-cross-crate.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-default-methods.stderr b/src/test/ui/specialization/specialization-default-methods.stderr index 4fa19adad06..ef6365ed31f 100644 --- a/src/test/ui/specialization/specialization-default-methods.stderr +++ b/src/test/ui/specialization/specialization-default-methods.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-default-projection.stderr b/src/test/ui/specialization/specialization-default-projection.stderr index 456eb6d5ca5..445bc1646f0 100644 --- a/src/test/ui/specialization/specialization-default-projection.stderr +++ b/src/test/ui/specialization/specialization-default-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/specialization-default-projection.rs:21:5 diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr index 5acfb53e206..5ba38facee0 100644 --- a/src/test/ui/specialization/specialization-default-types.stderr +++ b/src/test/ui/specialization/specialization-default-types.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:15:9 diff --git a/src/test/ui/specialization/specialization-no-default.stderr b/src/test/ui/specialization/specialization-no-default.stderr index bb8b2a6c98e..711c1fda149 100644 --- a/src/test/ui/specialization/specialization-no-default.stderr +++ b/src/test/ui/specialization/specialization-no-default.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0520]: `foo` specializes an item from a parent `impl`, but that item is not marked `default` --> $DIR/specialization-no-default.rs:20:5 diff --git a/src/test/ui/specialization/specialization-on-projection.stderr b/src/test/ui/specialization/specialization-on-projection.stderr index d91668d10c5..d051ffe0a02 100644 --- a/src/test/ui/specialization/specialization-on-projection.stderr +++ b/src/test/ui/specialization/specialization-on-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-out-of-order.stderr b/src/test/ui/specialization/specialization-out-of-order.stderr index a17f9f11a3f..785ec29239b 100644 --- a/src/test/ui/specialization/specialization-out-of-order.stderr +++ b/src/test/ui/specialization/specialization-out-of-order.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-overlap-negative.stderr b/src/test/ui/specialization/specialization-overlap-negative.stderr index 6141174ba8c..552b04a6019 100644 --- a/src/test/ui/specialization/specialization-overlap-negative.stderr +++ b/src/test/ui/specialization/specialization-overlap-negative.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `std::marker::Send` for type `TestType<_>`: --> $DIR/specialization-overlap-negative.rs:9:1 diff --git a/src/test/ui/specialization/specialization-overlap-projection.stderr b/src/test/ui/specialization/specialization-overlap-projection.stderr index 6f1a594bacb..c92db73074d 100644 --- a/src/test/ui/specialization/specialization-overlap-projection.stderr +++ b/src/test/ui/specialization/specialization-overlap-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-overlap.stderr b/src/test/ui/specialization/specialization-overlap.stderr index cf0f186a183..7e5c96ac1c8 100644 --- a/src/test/ui/specialization/specialization-overlap.stderr +++ b/src/test/ui/specialization/specialization-overlap.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0119]: conflicting implementations of trait `Foo` for type `std::vec::Vec<_>`: --> $DIR/specialization-overlap.rs:5:1 diff --git a/src/test/ui/specialization/specialization-polarity.stderr b/src/test/ui/specialization/specialization-polarity.stderr index c44af22b8e6..be013552f5d 100644 --- a/src/test/ui/specialization/specialization-polarity.stderr +++ b/src/test/ui/specialization/specialization-polarity.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `Foo` for type `u8`: --> $DIR/specialization-polarity.rs:10:1 diff --git a/src/test/ui/specialization/specialization-projection-alias.stderr b/src/test/ui/specialization/specialization-projection-alias.stderr index 0c3659a8f7a..6d2bca5d2df 100644 --- a/src/test/ui/specialization/specialization-projection-alias.stderr +++ b/src/test/ui/specialization/specialization-projection-alias.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-projection.stderr b/src/test/ui/specialization/specialization-projection.stderr index c5c86f5108e..0f1ecf5e379 100644 --- a/src/test/ui/specialization/specialization-projection.stderr +++ b/src/test/ui/specialization/specialization-projection.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-super-traits.stderr b/src/test/ui/specialization/specialization-super-traits.stderr index 05bdfd40136..165703d6365 100644 --- a/src/test/ui/specialization/specialization-super-traits.stderr +++ b/src/test/ui/specialization/specialization-super-traits.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr index 6284dd8f3f7..d30f7af2cbd 100644 --- a/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr +++ b/src/test/ui/specialization/specialization-translate-projections-with-lifetimes.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-translate-projections-with-params.stderr b/src/test/ui/specialization/specialization-translate-projections-with-params.stderr index b17794173c5..1762248f695 100644 --- a/src/test/ui/specialization/specialization-translate-projections-with-params.stderr +++ b/src/test/ui/specialization/specialization-translate-projections-with-params.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/specialization/specialization-translate-projections.stderr b/src/test/ui/specialization/specialization-translate-projections.stderr index fbb28e60640..94a0e79dd56 100644 --- a/src/test/ui/specialization/specialization-translate-projections.stderr +++ b/src/test/ui/specialization/specialization-translate-projections.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index c1eea56f70d..8a9a1e57935 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -13,7 +13,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | - ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL + ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL | LL | pub struct BufWriter<W: Write> { | ----- required by this bound in `BufWriter` @@ -26,7 +26,7 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | - ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL + ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL | LL | pub struct BufWriter<W: Write> { | ----- required by this bound in `BufWriter` @@ -39,7 +39,7 @@ error[E0599]: no method named `write_fmt` found for struct `BufWriter<&dyn std:: LL | writeln!(fp, "hello world").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `BufWriter<&dyn std::io::Write>` | - ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL + ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL | LL | pub struct BufWriter<W: Write> { | ------------------------------ doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write` diff --git a/src/test/ui/symbol-names/issue-75326.legacy.stderr b/src/test/ui/symbol-names/issue-75326.legacy.stderr new file mode 100644 index 00000000000..5f822f6660c --- /dev/null +++ b/src/test/ui/symbol-names/issue-75326.legacy.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next17SYMBOL_HASH) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next::SYMBOL_HASH) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/symbol-names/issue-75326.rs b/src/test/ui/symbol-names/issue-75326.rs new file mode 100644 index 00000000000..ce315164cef --- /dev/null +++ b/src/test/ui/symbol-names/issue-75326.rs @@ -0,0 +1,58 @@ +// build-fail +// ignore-tidy-linelength +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy +//[v0]compile-flags: -Z symbol-mangling-version=v0 +//[legacy]normalize-stderr-32bit: "h[\d\w]+" -> "SYMBOL_HASH" +//[legacy]normalize-stderr-64bit: "h[\d\w]+" -> "SYMBOL_HASH" + +#![feature(rustc_attrs)] + +pub(crate) struct Foo<I, E>(I, E); + +pub trait Iterator2 { + type Item; + + fn next(&mut self) -> Option<Self::Item>; + + fn find<P>(&mut self, predicate: P) -> Option<Self::Item> + where + Self: Sized, + P: FnMut(&Self::Item) -> bool, + { + unimplemented!() + } +} + +struct Bar; + +impl Iterator2 for Bar { + type Item = (u32, u16); + + fn next(&mut self) -> Option<Self::Item> { + unimplemented!() + } +} + +impl<I, T, E> Iterator2 for Foo<I, E> +where + I: Iterator2<Item = (T, E)>, +{ + type Item = T; + + #[rustc_symbol_name] + //[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next + //[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next + //[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next) + //[v0]~^^^^ ERROR symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) + //[v0]~| ERROR demangling(<issue_75326[317d481089b8c8fe]::Foo<_, _> as issue_75326[317d481089b8c8fe]::Iterator2>::next) + //[v0]~| ERROR demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next) + fn next(&mut self) -> Option<Self::Item> { + self.find(|_| true) + } +} + +fn main() { + let mut a = Foo(Bar, 1u16); + let _ = a.next(); +} diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr new file mode 100644 index 00000000000..59bdfa8ca36 --- /dev/null +++ b/src/test/ui/symbol-names/issue-75326.v0.stderr @@ -0,0 +1,20 @@ +error: symbol-name(_RNvXINICs4fqI2P2rA04_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<issue_75326[317d481089b8c8fe]::Foo<_, _> as issue_75326[317d481089b8c8fe]::Iterator2>::next) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next) + --> $DIR/issue-75326.rs:43:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/traits/assoc_type_bound_with_struct.rs b/src/test/ui/traits/assoc_type_bound_with_struct.rs new file mode 100644 index 00000000000..c66009fe24c --- /dev/null +++ b/src/test/ui/traits/assoc_type_bound_with_struct.rs @@ -0,0 +1,19 @@ +trait Bar { + type Baz; +} + +struct Foo<T> where T: Bar, <T as Bar>::Baz: String { //~ ERROR expected trait, found struct + t: T, +} + +struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found struct + t: &'a T, +} + +fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String { //~ ERROR expected trait, found struct +} + +fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { //~ ERROR expected trait, found +} + +fn main() {} diff --git a/src/test/ui/traits/assoc_type_bound_with_struct.stderr b/src/test/ui/traits/assoc_type_bound_with_struct.stderr new file mode 100644 index 00000000000..7cf872eb6ac --- /dev/null +++ b/src/test/ui/traits/assoc_type_bound_with_struct.stderr @@ -0,0 +1,83 @@ +error[E0404]: expected trait, found struct `String` + --> $DIR/assoc_type_bound_with_struct.rs:5:46 + | +LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: String { + | ^^^^^^ not a trait + | + ::: $SRC_DIR/alloc/src/string.rs:LL:COL + | +LL | pub trait ToString { + | ------------------ similarly named trait `ToString` defined here + | +help: constrain the associated type to `String` + | +LL | struct Foo<T> where T: Bar, T: Bar<Baz = String> { + | ^^^^^^^^^^^^^^^^^^^^ +help: a trait with a similar name exists + | +LL | struct Foo<T> where T: Bar, <T as Bar>::Baz: ToString { + | ^^^^^^^^ + +error[E0404]: expected trait, found struct `String` + --> $DIR/assoc_type_bound_with_struct.rs:9:54 + | +LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: String { + | ^^^^^^ not a trait + | + ::: $SRC_DIR/alloc/src/string.rs:LL:COL + | +LL | pub trait ToString { + | ------------------ similarly named trait `ToString` defined here + | +help: constrain the associated type to `String` + | +LL | struct Qux<'a, T> where T: Bar, &'a T: Bar<Baz = String> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: a trait with a similar name exists + | +LL | struct Qux<'a, T> where T: Bar, <&'a T as Bar>::Baz: ToString { + | ^^^^^^^^ + +error[E0404]: expected trait, found struct `String` + --> $DIR/assoc_type_bound_with_struct.rs:13:45 + | +LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: String { + | ^^^^^^ not a trait + | + ::: $SRC_DIR/alloc/src/string.rs:LL:COL + | +LL | pub trait ToString { + | ------------------ similarly named trait `ToString` defined here + | +help: constrain the associated type to `String` + | +LL | fn foo<T: Bar>(_: T) where T: Bar<Baz = String> { + | ^^^^^^^^^^^^^^^^^^^^ +help: a trait with a similar name exists + | +LL | fn foo<T: Bar>(_: T) where <T as Bar>::Baz: ToString { + | ^^^^^^^^ + +error[E0404]: expected trait, found struct `String` + --> $DIR/assoc_type_bound_with_struct.rs:16:57 + | +LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: String { + | ^^^^^^ not a trait + | + ::: $SRC_DIR/alloc/src/string.rs:LL:COL + | +LL | pub trait ToString { + | ------------------ similarly named trait `ToString` defined here + | +help: constrain the associated type to `String` + | +LL | fn qux<'a, T: Bar>(_: &'a T) where &'a T: Bar<Baz = String> { + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: a trait with a similar name exists + | +LL | fn qux<'a, T: Bar>(_: &'a T) where <&'a T as Bar>::Baz: ToString { + | ^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0404`. diff --git a/src/test/ui/traits/negative-impls/negative-default-impls.stderr b/src/test/ui/traits/negative-impls/negative-default-impls.stderr index 50e74373b53..ceb86559d85 100644 --- a/src/test/ui/traits/negative-impls/negative-default-impls.stderr +++ b/src/test/ui/traits/negative-impls/negative-default-impls.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0750]: negative impls cannot be default impls --> $DIR/negative-default-impls.rs:9:1 diff --git a/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr b/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr index 8b536de3786..9a846143d3d 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr +++ b/src/test/ui/traits/negative-impls/negative-specializes-negative.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr index 89ef15e89ac..77b4373a273 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive-item.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/negative-specializes-positive-item.rs:11:1 diff --git a/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr index e45d5a251ab..e5dc81b3eb7 100644 --- a/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr +++ b/src/test/ui/traits/negative-impls/negative-specializes-positive.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/negative-specializes-positive.rs:7:1 diff --git a/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr index 49c16d47404..c091bc81da3 100644 --- a/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr +++ b/src/test/ui/traits/negative-impls/positive-specializes-negative.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete error[E0751]: found both positive and negative implementation of trait `MyTrait` for type `u32`: --> $DIR/positive-specializes-negative.rs:7:1 diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.rs b/src/test/ui/traits/trait-bounds-not-on-struct.rs index c6e93e75525..8633e9d7a4c 100644 --- a/src/test/ui/traits/trait-bounds-not-on-struct.rs +++ b/src/test/ui/traits/trait-bounds-not-on-struct.rs @@ -1,9 +1,38 @@ +// We don't need those errors. Ideally we would silence them, but to do so we need to move the +// lint from being an early-lint during parsing to a late-lint, because it needs to be aware of +// the types involved. #![allow(bare_trait_objects)] struct Foo; fn foo(_x: Box<Foo + Send>) { } //~ ERROR expected trait, found struct `Foo` -type A<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec` +type TypeAlias<T> = Box<dyn Vec<T>>; //~ ERROR expected trait, found struct `Vec` -fn main() { } +struct A; +fn a() -> A + 'static { //~ ERROR expected trait, found + A +} +fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) { //~ ERROR expected trait, found + panic!() +} +fn c() -> 'static + A { //~ ERROR expected trait, found + A +} +fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) { //~ ERROR expected trait, found + panic!() +} +fn e() -> 'static + A + 'static { //~ ERROR expected trait, found +//~^ ERROR only a single explicit lifetime bound is permitted + A +} +fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) { //~ ERROR expected trait, found +//~^ ERROR only a single explicit lifetime bound is permitted + panic!() +} +struct Traitor; +trait Trait {} +fn g() -> Traitor + 'static { //~ ERROR expected trait, found struct `Traitor` + A +} +fn main() {} diff --git a/src/test/ui/traits/trait-bounds-not-on-struct.stderr b/src/test/ui/traits/trait-bounds-not-on-struct.stderr index a649a4eee55..0f97e3bdf18 100644 --- a/src/test/ui/traits/trait-bounds-not-on-struct.stderr +++ b/src/test/ui/traits/trait-bounds-not-on-struct.stderr @@ -1,15 +1,168 @@ +error[E0226]: only a single explicit lifetime bound is permitted + --> $DIR/trait-bounds-not-on-struct.rs:25:25 + | +LL | fn e() -> 'static + A + 'static { + | ^^^^^^^ + +error[E0226]: only a single explicit lifetime bound is permitted + --> $DIR/trait-bounds-not-on-struct.rs:29:53 + | +LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) { + | ^^ + error[E0404]: expected trait, found struct `Foo` - --> $DIR/trait-bounds-not-on-struct.rs:5:16 + --> $DIR/trait-bounds-not-on-struct.rs:8:16 | LL | fn foo(_x: Box<Foo + Send>) { } | ^^^ not a trait + | +help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way + --> $DIR/trait-bounds-not-on-struct.rs:8:22 + | +LL | fn foo(_x: Box<Foo + Send>) { } + | --- ^^^^ ...because of this bound + | | + | expected this type to be a trait... error[E0404]: expected trait, found struct `Vec` - --> $DIR/trait-bounds-not-on-struct.rs:7:21 + --> $DIR/trait-bounds-not-on-struct.rs:10:29 + | +LL | type TypeAlias<T> = Box<dyn Vec<T>>; + | ^^^^^^ not a trait + +error[E0404]: expected trait, found struct `A` + --> $DIR/trait-bounds-not-on-struct.rs:13:11 + | +LL | fn a() -> A + 'static { + | ^ not a trait + | +help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way + --> $DIR/trait-bounds-not-on-struct.rs:13:15 + | +LL | fn a() -> A + 'static { + | - ^^^^^^^ ...because of this bound + | | + | expected this type to be a trait... +help: if you meant to use a type and not a trait here, remove the bounds + | +LL | fn a() -> A { + | -- + +error[E0404]: expected trait, found enum `Result` + --> $DIR/trait-bounds-not-on-struct.rs:16:34 + | +LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) { + | ^^^^^^^^^^^ not a trait + | +help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way + --> $DIR/trait-bounds-not-on-struct.rs:16:48 + | +LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E> + 'a>) { + | ----------- ^^ ...because of this bound + | | + | expected this type to be a trait... +help: if you meant to use a type and not a trait here, remove the bounds + | +LL | fn b<'a,T,E>(iter: Iterator<Item=Result<T,E>>) { + | -- + +error[E0404]: expected trait, found struct `A` + --> $DIR/trait-bounds-not-on-struct.rs:19:21 + | +LL | fn c() -> 'static + A { + | ^ not a trait + | +help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way + --> $DIR/trait-bounds-not-on-struct.rs:19:11 + | +LL | fn c() -> 'static + A { + | ^^^^^^^ - expected this type to be a trait... + | | + | ...because of this bound +help: if you meant to use a type and not a trait here, remove the bounds + | +LL | fn c() -> A { + | -- + +error[E0404]: expected trait, found enum `Result` + --> $DIR/trait-bounds-not-on-struct.rs:22:39 + | +LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) { + | ^^^^^^^^^^^ not a trait + | +help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way + --> $DIR/trait-bounds-not-on-struct.rs:22:34 + | +LL | fn d<'a,T,E>(iter: Iterator<Item='a + Result<T,E>>) { + | ^^ ----------- expected this type to be a trait... + | | + | ...because of this bound +help: if you meant to use a type and not a trait here, remove the bounds + | +LL | fn d<'a,T,E>(iter: Iterator<Item=Result<T,E>>) { + | -- + +error[E0404]: expected trait, found struct `A` + --> $DIR/trait-bounds-not-on-struct.rs:25:21 + | +LL | fn e() -> 'static + A + 'static { + | ^ not a trait + | +help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way + --> $DIR/trait-bounds-not-on-struct.rs:25:11 + | +LL | fn e() -> 'static + A + 'static { + | ^^^^^^^ - ^^^^^^^ ...because of these bounds + | | + | expected this type to be a trait... +help: if you meant to use a type and not a trait here, remove the bounds + | +LL | fn e() -> A { + | --- + +error[E0404]: expected trait, found enum `Result` + --> $DIR/trait-bounds-not-on-struct.rs:29:39 + | +LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) { + | ^^^^^^^^^^^ not a trait + | +help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way + --> $DIR/trait-bounds-not-on-struct.rs:29:34 + | +LL | fn f<'a,T,E>(iter: Iterator<Item='a + Result<T,E> + 'a>) { + | ^^ ----------- ^^ ...because of these bounds + | | + | expected this type to be a trait... +help: if you meant to use a type and not a trait here, remove the bounds + | +LL | fn f<'a,T,E>(iter: Iterator<Item=Result<T,E>>) { + | -- -- + +error[E0404]: expected trait, found struct `Traitor` + --> $DIR/trait-bounds-not-on-struct.rs:35:11 + | +LL | trait Trait {} + | ----------- similarly named trait `Trait` defined here +LL | fn g() -> Traitor + 'static { + | ^^^^^^^ not a trait + | +help: `+` is used to constrain a "trait object" type with lifetimes or auto-traits; structs and enums can't be bound in that way + --> $DIR/trait-bounds-not-on-struct.rs:35:21 + | +LL | fn g() -> Traitor + 'static { + | ------- ^^^^^^^ ...because of this bound + | | + | expected this type to be a trait... +help: if you meant to use a type and not a trait here, remove the bounds + | +LL | fn g() -> Traitor { + | -- +help: a trait with a similar name exists | -LL | type A<T> = Box<dyn Vec<T>>; - | ^^^^^^ not a trait +LL | fn g() -> Trait + 'static { + | ^^^^^ -error: aborting due to 2 previous errors +error: aborting due to 11 previous errors -For more information about this error, try `rustc --explain E0404`. +Some errors have detailed explanations: E0226, E0404. +For more information about an error, try `rustc --explain E0226`. diff --git a/src/test/ui/transmute-specialization.stderr b/src/test/ui/transmute-specialization.stderr index 02315051d30..a0ea72415a1 100644 --- a/src/test/ui/transmute-specialization.stderr +++ b/src/test/ui/transmute-specialization.stderr @@ -6,6 +6,7 @@ LL | #![feature(specialization)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information + = help: consider using `min_specialization` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/transmute/main.rs b/src/test/ui/transmute/main.rs index ea233a47a78..cb46fc5ec46 100644 --- a/src/test/ui/transmute/main.rs +++ b/src/test/ui/transmute/main.rs @@ -1,9 +1,6 @@ // normalize-stderr-32bit: "`&str` \(64 bits\)" -> "`&str` ($$STR bits)" // normalize-stderr-64bit: "`&str` \(128 bits\)" -> "`&str` ($$STR bits)" - - -#![feature(untagged_unions)] use std::mem::transmute; pub trait TypeConstructor<'a> { diff --git a/src/test/ui/transmute/main.stderr b/src/test/ui/transmute/main.stderr index 4e781318329..f48562094a4 100644 --- a/src/test/ui/transmute/main.stderr +++ b/src/test/ui/transmute/main.stderr @@ -1,5 +1,5 @@ error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:16:5 + --> $DIR/main.rs:13:5 | LL | transmute(x) | ^^^^^^^^^ @@ -7,7 +7,7 @@ LL | transmute(x) = note: `<C as TypeConstructor>::T` does not have a fixed size error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:20:17 + --> $DIR/main.rs:17:17 | LL | let x: u8 = transmute(10u16); | ^^^^^^^^^ @@ -16,7 +16,7 @@ LL | let x: u8 = transmute(10u16); = note: target type: `u8` (8 bits) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:24:17 + --> $DIR/main.rs:21:17 | LL | let x: u8 = transmute("test"); | ^^^^^^^^^ @@ -25,7 +25,7 @@ LL | let x: u8 = transmute("test"); = note: target type: `u8` (8 bits) error[E0512]: cannot transmute between types of different sizes, or dependently-sized types - --> $DIR/main.rs:29:18 + --> $DIR/main.rs:26:18 | LL | let x: Foo = transmute(10); | ^^^^^^^^^ diff --git a/src/test/ui/tuple/index-invalid.stderr b/src/test/ui/tuple/index-invalid.stderr index 800b5a31d98..8d22f458a6c 100644 --- a/src/test/ui/tuple/index-invalid.stderr +++ b/src/test/ui/tuple/index-invalid.stderr @@ -2,19 +2,19 @@ error[E0609]: no field `1` on type `(((),),)` --> $DIR/index-invalid.rs:2:22 | LL | let _ = (((),),).1.0; - | ^^^ + | ^ error[E0609]: no field `1` on type `((),)` - --> $DIR/index-invalid.rs:4:22 + --> $DIR/index-invalid.rs:4:24 | LL | let _ = (((),),).0.1; - | ^^^ + | ^ error[E0609]: no field `000` on type `(((),),)` --> $DIR/index-invalid.rs:6:22 | LL | let _ = (((),),).000.000; - | ^^^^^^^ + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr index 46e7dd0c517..20e26058451 100644 --- a/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr +++ b/src/test/ui/type-alias-enum-variants/enum-variant-priority-higher-than-other-inherent.stderr @@ -1,13 +1,16 @@ error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:21:5 | -LL | V(u8) - | ----- defined here -... LL | <E>::V(); | ^^^^^^-- supplied 0 arguments | | | expected 1 argument + | +note: tuple variant defined here + --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:5:5 + | +LL | V(u8) + | ^^^^^ error[E0308]: mismatched types --> $DIR/enum-variant-priority-higher-than-other-inherent.rs:22:17 diff --git a/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr b/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr index e0c1b023861..c5b22f0026d 100644 --- a/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr +++ b/src/test/ui/type-alias-impl-trait/assoc-type-const.stderr @@ -6,6 +6,7 @@ LL | #![feature(const_generics)] | = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information + = help: consider using `min_const_generics` instead, which is more stable and complete warning: 1 warning emitted diff --git a/src/test/ui/type-alias-impl-trait/issue-52843.rs b/src/test/ui/type-alias-impl-trait/issue-52843.rs new file mode 100644 index 00000000000..b24959d7207 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-52843.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +type Foo<T> = impl Default; +//~^ ERROR: the trait bound `T: Default` is not satisfied + +#[allow(unused)] +fn foo<T: Default>(t: T) -> Foo<T> { + t +} + +struct NotDefault; + +fn main() { + let _ = Foo::<NotDefault>::default(); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-52843.stderr b/src/test/ui/type-alias-impl-trait/issue-52843.stderr new file mode 100644 index 00000000000..25db8dfabfc --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-52843.stderr @@ -0,0 +1,14 @@ +error[E0277]: the trait bound `T: Default` is not satisfied + --> $DIR/issue-52843.rs:3:15 + | +LL | type Foo<T> = impl Default; + | ^^^^^^^^^^^^ the trait `Default` is not implemented for `T` + | +help: consider restricting type parameter `T` + | +LL | type Foo<T: Default> = impl Default; + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/unboxed-closures/issue-53448.rs b/src/test/ui/unboxed-closures/issue-53448.rs new file mode 100644 index 00000000000..5c82a56e77e --- /dev/null +++ b/src/test/ui/unboxed-closures/issue-53448.rs @@ -0,0 +1,15 @@ +#![feature(unboxed_closures)] + +trait Lt<'a> { + type T; +} +impl<'a> Lt<'a> for () { + type T = (); +} + +fn main() { + let v: <() as Lt<'_>>::T = (); + let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {}; + //~^ ERROR: the size for values of type `<() as Lt<'_>>::T` cannot be known + f(v); +} diff --git a/src/test/ui/unboxed-closures/issue-53448.stderr b/src/test/ui/unboxed-closures/issue-53448.stderr new file mode 100644 index 00000000000..bece9eedc7f --- /dev/null +++ b/src/test/ui/unboxed-closures/issue-53448.stderr @@ -0,0 +1,20 @@ +error[E0277]: the size for values of type `<() as Lt<'_>>::T` cannot be known at compilation time + --> $DIR/issue-53448.rs:12:54 + | +LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: <() as Lt<'_>>::T| {}; + | ^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `<() as Lt<'_>>::T` + = help: unsized locals are gated as an unstable feature +help: consider further restricting the associated type + | +LL | fn main() where <() as Lt<'_>>::T: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: function arguments must have a statically known size, borrowed types always have a known size + | +LL | let f: &mut dyn FnMut<(_,), Output = ()> = &mut |_: &<() as Lt<'_>>::T| {}; + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/union/union-align.rs b/src/test/ui/union/union-align.rs index edd83a51169..1340ae43cd6 100644 --- a/src/test/ui/union/union-align.rs +++ b/src/test/ui/union/union-align.rs @@ -1,8 +1,6 @@ // run-pass #![allow(dead_code)] -#![feature(untagged_unions)] - use std::mem::{size_of, size_of_val, align_of, align_of_val}; #[repr(align(16))] @@ -35,6 +33,7 @@ mod hybrid { use std::mem::{size_of, align_of}; #[repr(align(16))] + #[derive(Copy, Clone)] struct S1 { a: u16, b: u8, diff --git a/src/test/ui/union/union-copy.rs b/src/test/ui/union/union-copy.rs index 8318f96940e..5c3f8d90898 100644 --- a/src/test/ui/union/union-copy.rs +++ b/src/test/ui/union/union-copy.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - #[derive(Clone)] union U { a: u8 @@ -7,7 +5,7 @@ union U { #[derive(Clone)] union W { - a: String + a: std::mem::ManuallyDrop<String> } impl Copy for U {} // OK diff --git a/src/test/ui/union/union-copy.stderr b/src/test/ui/union/union-copy.stderr index a875ff660f9..0f47bae7f0f 100644 --- a/src/test/ui/union/union-copy.stderr +++ b/src/test/ui/union/union-copy.stderr @@ -1,8 +1,8 @@ error[E0204]: the trait `Copy` may not be implemented for this type - --> $DIR/union-copy.rs:14:6 + --> $DIR/union-copy.rs:12:6 | -LL | a: String - | --------- this field does not implement `Copy` +LL | a: std::mem::ManuallyDrop<String> + | --------------------------------- this field does not implement `Copy` ... LL | impl Copy for W {} | ^^^^ diff --git a/src/test/ui/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr index fb16649767f..f7722764cd3 100644 --- a/src/test/ui/union/union-deref.stderr +++ b/src/test/ui/union/union-deref.stderr @@ -29,7 +29,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field --> $DIR/union-deref.rs:23:14 | LL | unsafe { u.f.0.0 = Vec::new() }; - | ^^^^^^^ + | ^^^^^ | = help: writing to this reference calls the destructor for the old value = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor @@ -38,7 +38,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field --> $DIR/union-deref.rs:25:19 | LL | unsafe { &mut u.f.0.0 }; - | ^^^^^^^ + | ^^^^^ | = help: writing to this reference calls the destructor for the old value = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor @@ -47,7 +47,7 @@ error: not automatically applying `DerefMut` on `ManuallyDrop` union field --> $DIR/union-deref.rs:27:14 | LL | unsafe { u.f.0.0.push(0) }; - | ^^^^^^^ + | ^^^^^ | = help: writing to this reference calls the destructor for the old value = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor diff --git a/src/test/ui/union/union-derive-clone.rs b/src/test/ui/union/union-derive-clone.rs index 8126980604a..753a9f74d03 100644 --- a/src/test/ui/union/union-derive-clone.rs +++ b/src/test/ui/union/union-derive-clone.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - use std::mem::ManuallyDrop; #[derive(Clone)] //~ ERROR the trait bound `U1: Copy` is not satisfied diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index 7a59f539c37..e18f457a8b6 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `U1: Copy` is not satisfied - --> $DIR/union-derive-clone.rs:5:10 + --> $DIR/union-derive-clone.rs:3:10 | LL | #[derive(Clone)] | ^^^^^ the trait `Copy` is not implemented for `U1` @@ -12,7 +12,7 @@ LL | pub struct AssertParamIsCopy<T: Copy + ?Sized> { = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error[E0599]: no method named `clone` found for union `U5<CloneNoCopy>` in the current scope - --> $DIR/union-derive-clone.rs:37:15 + --> $DIR/union-derive-clone.rs:35:15 | LL | union U5<T> { | ----------- diff --git a/src/test/ui/union/union-derive-eq.rs b/src/test/ui/union/union-derive-eq.rs index ac5808e4361..e689f8c27d7 100644 --- a/src/test/ui/union/union-derive-eq.rs +++ b/src/test/ui/union/union-derive-eq.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - #[derive(Eq)] // OK union U1 { a: u8, @@ -7,7 +5,7 @@ union U1 { impl PartialEq for U1 { fn eq(&self, rhs: &Self) -> bool { true } } -#[derive(PartialEq)] +#[derive(PartialEq, Copy, Clone)] struct PartialEqNotEq; #[derive(Eq)] diff --git a/src/test/ui/union/union-derive-eq.stderr b/src/test/ui/union/union-derive-eq.stderr index c4d437c6cdd..0591d12d598 100644 --- a/src/test/ui/union/union-derive-eq.stderr +++ b/src/test/ui/union/union-derive-eq.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied - --> $DIR/union-derive-eq.rs:15:5 + --> $DIR/union-derive-eq.rs:13:5 | LL | a: PartialEqNotEq, | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq` diff --git a/src/test/ui/union/union-derive-rpass.rs b/src/test/ui/union/union-derive-rpass.rs index b2f7ae679fd..db18a81c1f6 100644 --- a/src/test/ui/union/union-derive-rpass.rs +++ b/src/test/ui/union/union-derive-rpass.rs @@ -4,8 +4,6 @@ // Some traits can be derived for unions. -#![feature(untagged_unions)] - #[derive( Copy, Clone, diff --git a/src/test/ui/union/union-drop-assign.rs b/src/test/ui/union/union-drop-assign.rs index f1511b0a601..215666bdd9d 100644 --- a/src/test/ui/union/union-drop-assign.rs +++ b/src/test/ui/union/union-drop-assign.rs @@ -3,8 +3,6 @@ // Drop works for union itself. -#![feature(untagged_unions)] - use std::mem::ManuallyDrop; struct S; diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs index 4df3ed50282..9edf5827511 100644 --- a/src/test/ui/union/union-drop.rs +++ b/src/test/ui/union/union-drop.rs @@ -4,8 +4,7 @@ // Drop works for union itself. -#![feature(untagged_unions)] - +#[derive(Copy, Clone)] struct S; union U { diff --git a/src/test/ui/union/union-generic-rpass.rs b/src/test/ui/union/union-generic-rpass.rs index eb169c516d2..69837f31cab 100644 --- a/src/test/ui/union/union-generic-rpass.rs +++ b/src/test/ui/union/union-generic-rpass.rs @@ -1,8 +1,6 @@ // run-pass #![allow(dead_code)] -#![feature(untagged_unions)] - use std::mem::ManuallyDrop; union MaybeItem<T: Iterator> { @@ -16,7 +14,7 @@ union U<A, B> where A: Copy, B: Copy { } unsafe fn union_transmute<A, B>(a: A) -> B where A: Copy, B: Copy { - U { a: a }.b + U { a }.b } fn main() { diff --git a/src/test/ui/union/union-manuallydrop-rpass.rs b/src/test/ui/union/union-manuallydrop-rpass.rs index a43a5050865..977d12f1086 100644 --- a/src/test/ui/union/union-manuallydrop-rpass.rs +++ b/src/test/ui/union/union-manuallydrop-rpass.rs @@ -1,4 +1,3 @@ -#![feature(untagged_unions)] #![allow(dead_code)] // run-pass diff --git a/src/test/ui/union/union-nodrop.rs b/src/test/ui/union/union-nodrop.rs index 59282bec59b..bc58c5995cb 100644 --- a/src/test/ui/union/union-nodrop.rs +++ b/src/test/ui/union/union-nodrop.rs @@ -1,7 +1,5 @@ // run-pass -#![feature(untagged_unions)] - #![allow(dead_code)] use std::mem::needs_drop; diff --git a/src/test/ui/union/union-overwrite.rs b/src/test/ui/union/union-overwrite.rs index 8234beb74a8..399ed9ae458 100644 --- a/src/test/ui/union/union-overwrite.rs +++ b/src/test/ui/union/union-overwrite.rs @@ -1,5 +1,4 @@ // run-pass -#![feature(untagged_unions)] #[repr(C)] #[derive(Copy, Clone)] diff --git a/src/test/ui/union/union-packed.rs b/src/test/ui/union/union-packed.rs index ceb35d94656..9cde44c06bd 100644 --- a/src/test/ui/union/union-packed.rs +++ b/src/test/ui/union/union-packed.rs @@ -2,8 +2,6 @@ #![allow(dead_code)] #![allow(non_snake_case)] -#![feature(untagged_unions)] - use std::mem::{size_of, size_of_val, align_of, align_of_val}; struct S { @@ -118,6 +116,7 @@ mod hybrid { use std::mem::{size_of, align_of}; #[repr(packed)] + #[derive(Copy, Clone)] struct S1 { a: u16, b: u8, diff --git a/src/test/ui/union/union-unsafe.rs b/src/test/ui/union/union-unsafe.rs index 8535cbd019c..10f0c467560 100644 --- a/src/test/ui/union/union-unsafe.rs +++ b/src/test/ui/union/union-unsafe.rs @@ -1,4 +1,3 @@ -#![feature(untagged_unions)] use std::mem::ManuallyDrop; union U1 { diff --git a/src/test/ui/union/union-unsafe.stderr b/src/test/ui/union/union-unsafe.stderr index e020dab63f8..b50d9e17506 100644 --- a/src/test/ui/union/union-unsafe.stderr +++ b/src/test/ui/union/union-unsafe.stderr @@ -1,5 +1,5 @@ error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:22:5 + --> $DIR/union-unsafe.rs:21:5 | LL | u3.a = ManuallyDrop::new(T::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field @@ -7,7 +7,7 @@ LL | u3.a = ManuallyDrop::new(T::default()); = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:23:6 + --> $DIR/union-unsafe.rs:22:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -15,7 +15,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:29:6 + --> $DIR/union-unsafe.rs:28:6 | LL | *u3.a = T::default(); | ^^^^ access to union field @@ -23,7 +23,7 @@ LL | *u3.a = T::default(); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:37:13 + --> $DIR/union-unsafe.rs:36:13 | LL | let a = u1.a; | ^^^^ access to union field @@ -31,7 +31,7 @@ LL | let a = u1.a; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:40:14 + --> $DIR/union-unsafe.rs:39:14 | LL | let U1 { a } = u1; | ^ access to union field @@ -39,7 +39,7 @@ LL | let U1 { a } = u1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:41:20 + --> $DIR/union-unsafe.rs:40:20 | LL | if let U1 { a: 12 } = u1 {} | ^^ access to union field @@ -47,7 +47,7 @@ LL | if let U1 { a: 12 } = u1 {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:45:5 + --> $DIR/union-unsafe.rs:44:5 | LL | u2.a = ManuallyDrop::new(String::from("new")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field @@ -55,7 +55,7 @@ LL | u2.a = ManuallyDrop::new(String::from("new")); = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:46:6 + --> $DIR/union-unsafe.rs:45:6 | LL | *u2.a = String::from("new"); | ^^^^ access to union field @@ -63,7 +63,7 @@ LL | *u2.a = String::from("new"); = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:50:6 + --> $DIR/union-unsafe.rs:49:6 | LL | *u3.a = 1; | ^^^^ access to union field @@ -71,7 +71,7 @@ LL | *u3.a = 1; = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: assignment to non-`Copy` union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:53:5 + --> $DIR/union-unsafe.rs:52:5 | LL | u3.a = ManuallyDrop::new(String::from("new")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to non-`Copy` union field @@ -79,7 +79,7 @@ LL | u3.a = ManuallyDrop::new(String::from("new")); = note: the previous content of the field will be dropped, which causes undefined behavior if the field was not properly initialized error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/union-unsafe.rs:54:6 + --> $DIR/union-unsafe.rs:53:6 | LL | *u3.a = String::from("new"); | ^^^^ access to union field diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 4ae4dbfc06e..4a2c710811f 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -14,3 +14,4 @@ tar = "0.4.29" sha2 = "0.9.1" rayon = "1.3.1" hex = "0.4.2" +num_cpus = "1.13.0" diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md index 26e96c9fd8f..b77c5a907c1 100644 --- a/src/tools/build-manifest/README.md +++ b/src/tools/build-manifest/README.md @@ -21,8 +21,8 @@ Then, you can generate the manifest and all the packages from `path/to/dist` to ``` $ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com \ - CHANNEL path/to/rust/repo + CHANNEL VERSION ``` Remember to replace `CHANNEL` with the channel you produced dist artifacts of -and `path/to/rust/repo` with the path to your checkout of the Rust repository. +and `VERSION` with the current Rust version. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index b35f3a595fb..1b780110456 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -22,6 +22,8 @@ use std::sync::Mutex; use std::time::Instant; static HOSTS: &[&str] = &[ + "aarch64-apple-darwin", + "aarch64-pc-windows-msvc", "aarch64-unknown-linux-gnu", "aarch64-unknown-linux-musl", "arm-unknown-linux-gnueabi", @@ -55,6 +57,7 @@ static HOSTS: &[&str] = &[ ]; static TARGETS: &[&str] = &[ + "aarch64-apple-darwin", "aarch64-apple-ios", "aarch64-fuchsia", "aarch64-linux-android", @@ -205,15 +208,20 @@ fn main() { // // Once the old release process is fully decommissioned, the environment variable, all the // related code in this tool and ./x.py dist hash-and-sign can be removed. - let legacy = env::var("BUILD_MANIFEST_LEGACY").is_ok(); - - // Avoid overloading the old server in legacy mode. - if legacy { - rayon::ThreadPoolBuilder::new() - .num_threads(1) - .build_global() - .expect("failed to initialize Rayon"); - } + let legacy = env::var_os("BUILD_MANIFEST_LEGACY").is_some(); + + let num_threads = if legacy { + // Avoid overloading the old server in legacy mode. + 1 + } else if let Some(num) = env::var_os("BUILD_MANIFEST_NUM_THREADS") { + num.to_str().unwrap().parse().expect("invalid number for BUILD_MANIFEST_NUM_THREADS") + } else { + num_cpus::get() + }; + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build_global() + .expect("failed to initialize Rayon"); let mut args = env::args().skip(1); let input = PathBuf::from(args.next().unwrap()); @@ -221,7 +229,6 @@ fn main() { let date = args.next().unwrap(); let s3_address = args.next().unwrap(); let channel = args.next().unwrap(); - let monorepo_path = args.next().unwrap(); // Do not ask for a passphrase while manually testing let mut passphrase = String::new(); @@ -231,7 +238,7 @@ fn main() { } Builder { - versions: Versions::new(&channel, &input, Path::new(&monorepo_path)).unwrap(), + versions: Versions::new(&channel, &input).unwrap(), input, output, @@ -252,12 +259,13 @@ impl Builder { } let manifest = self.build_manifest(); - let rust_version = self.versions.rustc_version(); self.write_channel_files(self.versions.channel(), &manifest); - if self.versions.channel() != rust_version { - self.write_channel_files(&rust_version, &manifest); - } if self.versions.channel() == "stable" { + // channel-rust-1.XX.YY.toml + let rust_version = self.versions.rustc_version(); + self.write_channel_files(rust_version, &manifest); + + // channel-rust-1.XX.toml let major_minor = rust_version.split('.').take(2).collect::<Vec<_>>().join("."); self.write_channel_files(&major_minor, &manifest); } diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs index 75b6979b54a..79f2ef8dfc4 100644 --- a/src/tools/build-manifest/src/versions.rs +++ b/src/tools/build-manifest/src/versions.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Error}; +use anyhow::Error; use flate2::read::GzDecoder; use std::collections::HashMap; use std::fs::File; @@ -7,6 +7,7 @@ use std::path::{Path, PathBuf}; use tar::Archive; const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu"; +const RUSTC_VERSION: &str = include_str!("../../../version"); #[derive(Debug, Hash, Eq, PartialEq, Clone)] pub(crate) enum PkgType { @@ -87,26 +88,13 @@ pub(crate) struct VersionInfo { pub(crate) struct Versions { channel: String, - rustc_version: String, dist_path: PathBuf, versions: HashMap<PkgType, VersionInfo>, } impl Versions { - pub(crate) fn new( - channel: &str, - dist_path: &Path, - monorepo_root: &Path, - ) -> Result<Self, Error> { - Ok(Self { - channel: channel.into(), - rustc_version: std::fs::read_to_string(monorepo_root.join("src").join("version")) - .context("failed to read the rustc version from src/version")? - .trim() - .to_string(), - dist_path: dist_path.into(), - versions: HashMap::new(), - }) + pub(crate) fn new(channel: &str, dist_path: &Path) -> Result<Self, Error> { + Ok(Self { channel: channel.into(), dist_path: dist_path.into(), versions: HashMap::new() }) } pub(crate) fn channel(&self) -> &str { @@ -184,10 +172,10 @@ impl Versions { ) -> Result<String, Error> { let component_name = package.tarball_component_name(); let version = match self.channel.as_str() { - "stable" => self.rustc_version.clone(), + "stable" => RUSTC_VERSION.into(), "beta" => "beta".into(), "nightly" => "nightly".into(), - _ => format!("{}-dev", self.rustc_version), + _ => format!("{}-dev", RUSTC_VERSION), }; if package.target_independent() { @@ -198,6 +186,6 @@ impl Versions { } pub(crate) fn rustc_version(&self) -> &str { - &self.rustc_version + RUSTC_VERSION } } diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 9d1a4863abd9237dbf9d1b74c78632b6a205f6b +Subproject 79b397d72c557eb6444a2ba0dc00a211a226a35 diff --git a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs index 1f06d2dbe91..d92eb86fb2e 100644 --- a/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs +++ b/src/tools/clippy/clippy_lints/src/trivially_copy_pass_by_ref.rs @@ -9,10 +9,10 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl, HirId, ItemKind, MutTy, Mutability, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::config::Config as SessionConfig; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; use rustc_target::abi::LayoutOf; +use rustc_target::spec::Target; use rustc_target::spec::abi::Abi; declare_clippy_lint! { @@ -60,9 +60,9 @@ pub struct TriviallyCopyPassByRef { } impl<'tcx> TriviallyCopyPassByRef { - pub fn new(limit: Option<u64>, target: &SessionConfig) -> Self { + pub fn new(limit: Option<u64>, target: &Target) -> Self { let limit = limit.unwrap_or_else(|| { - let bit_width = u64::from(target.ptr_width); + let bit_width = u64::from(target.pointer_width); // Cap the calculated bit width at 32-bits to reduce // portability problems between 32 and 64-bit targets let bit_width = cmp::min(bit_width, 32); diff --git a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs index 1b4f2034272..7cb7d0a26b6 100644 --- a/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_lints/src/utils/qualify_min_const_fn.rs @@ -282,7 +282,6 @@ fn check_terminator(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, terminator: &Termin TerminatorKind::SwitchInt { discr, switch_ty: _, - values: _, targets: _, } => check_operand(tcx, discr, span, body), diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs index f4f2259cefd..805828eece1 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -277,9 +277,9 @@ fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { // If backtraces are enabled, also print the query stack let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); - if backtrace { - TyCtxt::try_print_query_stack(&handler); - } + let num_frames = if backtrace { None } else { Some(2) }; + + TyCtxt::try_print_query_stack(&handler, num_frames); } fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<PathBuf> { @@ -357,7 +357,7 @@ pub fn main() { args.extend(vec!["--sysroot".into(), sys_root]); }; - return rustc_driver::run_compiler(&args, &mut DefaultCallbacks, None, None, None); + return rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run(); } if orig_args.iter().any(|a| a == "--version" || a == "-V") { @@ -420,6 +420,6 @@ pub fn main() { let mut default = DefaultCallbacks; let callbacks: &mut (dyn rustc_driver::Callbacks + Send) = if clippy_enabled { &mut clippy } else { &mut default }; - rustc_driver::run_compiler(&args, callbacks, None, None, None) + rustc_driver::RunCompiler::new(&args, callbacks).run() })) } diff --git a/src/tools/clippy/tests/ui/custom_ice_message.stderr b/src/tools/clippy/tests/ui/custom_ice_message.stderr index a9a65a38c10..a1b8e2ee162 100644 --- a/src/tools/clippy/tests/ui/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui/custom_ice_message.stderr @@ -9,3 +9,5 @@ note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy note: Clippy version: foo +query stack during panic: +end of query stack diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml index 0994cd20662..e5d870c039d 100644 --- a/src/tools/linkchecker/Cargo.toml +++ b/src/tools/linkchecker/Cargo.toml @@ -7,3 +7,7 @@ edition = "2018" [[bin]] name = "linkchecker" path = "main.rs" + +[dependencies] +regex = "1" +once_cell = "1" diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 4fe493a850d..f213944e0ab 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -21,6 +21,9 @@ use std::fs; use std::path::{Component, Path, PathBuf}; use std::rc::Rc; +use once_cell::sync::Lazy; +use regex::Regex; + use crate::Redirect::*; // Add linkcheck exceptions here @@ -50,6 +53,44 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ ("alloc/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]), ]; +#[rustfmt::skip] +const INTRA_DOC_LINK_EXCEPTIONS: &[(&str, &[&str])] = &[ + // This will never have links that are not in other pages. + // To avoid repeating the exceptions twice, an empty list means all broken links are allowed. + ("reference/print.html", &[]), + // All the reference 'links' are actually ENBF highlighted as code + ("reference/comments.html", &[ + "/</code> <code>!", + "*</code> <code>!", + ]), + ("reference/identifiers.html", &[ + "a</code>-<code>z</code> <code>A</code>-<code>Z", + "a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_", + "a</code>-<code>z</code> <code>A</code>-<code>Z</code>] [<code>a</code>-<code>z</code> <code>A</code>-<code>Z</code> <code>0</code>-<code>9</code> <code>_", + ]), + ("reference/tokens.html", &[ + "0</code>-<code>1", + "0</code>-<code>7", + "0</code>-<code>9", + "0</code>-<code>9", + "0</code>-<code>9</code> <code>a</code>-<code>f</code> <code>A</code>-<code>F", + ]), + ("reference/notation.html", &[ + "b</code> <code>B", + "a</code>-<code>z", + ]), + // This is being used in the sense of 'inclusive range', not a markdown link + ("core/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]), + ("std/ops/struct.RangeInclusive.html", &["begin</code>, <code>end"]), + ("core/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]), + ("alloc/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]), + ("std/slice/trait.SliceIndex.html", &["begin</code>, <code>end"]), + +]; + +static BROKEN_INTRA_DOC_LINK: Lazy<Regex> = + Lazy::new(|| Regex::new(r#"\[<code>(.*)</code>\]"#).unwrap()); + macro_rules! t { ($e:expr) => { match $e { @@ -138,6 +179,14 @@ fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) { } } +fn is_intra_doc_exception(file: &Path, link: &str) -> bool { + if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { + entry.1.is_empty() || entry.1.contains(&link) + } else { + false + } +} + fn is_exception(file: &Path, link: &str) -> bool { if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { entry.1.contains(&link) @@ -292,6 +341,19 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti } } }); + + // Search for intra-doc links that rustdoc didn't warn about + // FIXME(#77199, 77200) Rustdoc should just warn about these directly. + // NOTE: only looks at one line at a time; in practice this should find most links + for (i, line) in contents.lines().enumerate() { + for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) { + if !is_intra_doc_exception(file, &broken_link[1]) { + *errors = true; + print!("{}:{}: broken intra-doc link - ", pretty_file.display(), i + 1); + println!("{}", &broken_link[0]); + } + } + } Some(pretty_file) } diff --git a/src/tools/miri b/src/tools/miri -Subproject 3fafb835ea42e6e3af27f5dc8f26bda590cb49e +Subproject 1b3a27c4298ebed55851657934483366a02abc3 diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 33613e2dc10..7586f5aa3b5 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -33,7 +33,7 @@ MAINTAINERS = { 'rust-by-example': {'steveklabnik', 'marioidival'}, 'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'}, 'edition-guide': {'ehuss', 'steveklabnik'}, - 'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'}, + 'rustc-dev-guide': {'spastorino', 'amanjeev', 'JohnTitor'}, } LABELS = { diff --git a/src/tools/rls b/src/tools/rls -Subproject 9bfb47a79299d52f45304367762c9bfc96d9ed7 +Subproject 1f686d5f707269b1086f6afcdced36225c0c5ff diff --git a/triagebot.toml b/triagebot.toml index 8b7b536bcbf..fc733b9e45f 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -75,6 +75,7 @@ label = "I-prioritize" [autolabel."I-prioritize"] trigger_labels = [ + "regression-untriaged", "regression-from-stable-to-stable", "regression-from-stable-to-beta", "regression-from-stable-to-nightly", |
